Compare commits

..
Author SHA1 Message Date
Andoni Morales Alastruey 62614d8fa8 Bump lldb-mi commit hash
Fix #6874
2023-11-06 10:04:33 -08:00
Bob Brown fecfc08451 update changelog (#11532) 2023-10-16 11:30:46 -07:00
Sean McManus 62a03c2b21 Update changelog (2nd time) (#11527)
* Update changelog (2nd time).
2023-10-12 17:12:41 -07:00
Sean McManus 7273d6112b Update changelog for 1.18.0 (#11521) 2023-10-12 14:37:41 -07:00
Michelle Matias 74bddb82e5 Reuse workflow for CI builds (#11503) 2023-10-11 18:40:01 -07:00
Sean McManus 4af6ca9db0 Extract to function (#11467)
* Extract to function.
2023-10-11 17:27:36 -07:00
Michelle Matias 7e4ee25c48 remove CreateDeclDefnCommandArguments (#11517) 2023-10-10 12:31:23 -07:00
Sean McManus 6da9a49652 Updates for clang-tidy 17.0.1 (#11491) 2023-10-10 12:09:32 -07:00
Michelle Matias 51d88dbb24 Increase timeout for E2E tests (#11516) 2023-10-09 16:12:47 -07:00
Michelle Matias cd8ecf9060 Handle undefined environment variable (#11480) 2023-10-06 11:50:26 -07:00
Sean McManus 847ea0b73c Fix prepublish. (#11469) 2023-09-29 17:41:31 -07:00
Michelle Matias 68c7be9d9e Fix loading UI (#11486) 2023-09-29 13:06:38 -07:00
Michelle Matias 1bde544458 Add Include Header setting for refactoring actions (#11449) 2023-09-27 10:51:53 -07:00
Sean McManus f62cad6a2f Fix Initializing in the status bar instead of Indexing. (#11471) 2023-09-26 16:37:57 -07:00
Garrett Serack eec372a186 force module to node16 for ts-node (#11468) 2023-09-26 11:40:51 -07:00
Michelle Matias b98bb40a89 Update language server loc strings (#11445) 2023-09-25 17:29:54 -07:00
Colen Garoutte-Carson 4d1a2a0e90 Change how logging level is passed to native process (#11438) 2023-09-18 13:57:25 -07:00
Michelle Matias dec50598bc Remove obsolete experimental configuration code (#11427) 2023-09-14 17:12:03 -07:00
browntarik c5c64ad831 Update localized intellisense crash string (#11356)
* update localized intellisense crash string

* resolve string

* update hint

* resolve loc string

* resolve string locs

* resolve spelling error
2023-09-13 14:45:35 -07:00
Bob Brown 27153190e2 Compiler acquisition (#11286) 2023-09-13 11:54:29 -07:00
Sean McManus 2cc55ea6eb Add keyboard support for Inline Macro. (#11261)
* Add keyboard support for Inline Macro.
* Enable inline macro without hover.
* Standardize localize string naming.
* Fix spelling errors involving strings types.
2023-09-11 09:56:16 -07:00
Garrett Serack 121a657acb make translations export work correctly in CI (#11415) 2023-09-08 07:53:49 -07:00
dependabot[bot] 6a54986b3f Bump mongodb from 4.8.1 to 4.17.0 in /.github/actions (#11413)
Bumps [mongodb](https://github.com/mongodb/node-mongodb-native) from 4.8.1 to 4.17.0.
- [Release notes](https://github.com/mongodb/node-mongodb-native/releases)
- [Changelog](https://github.com/mongodb/node-mongodb-native/blob/v4.17.0/HISTORY.md)
- [Commits](https://github.com/mongodb/node-mongodb-native/compare/v4.8.1...v4.17.0)

---
updated-dependencies:
- dependency-name: mongodb
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <[email protected]>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-09-07 09:52:11 -07:00
Garrett Serack b4a70dfc0a Make yarn tasks imply yarn install where appropriate (#11394)
* made sure that yarn install gets called before compile

* Add some nice messages

* better detection

* cleaned up more

* more tweaks

* remove old checks

* let unit tests run without binaries

* turn off scenario tests until binaries can be installed

* add another rule
2023-09-06 07:47:36 -07:00
browntarik efa5c2244b Rework Database Storage Path Logic (#11309)
* Fix typo (#11275)

* rework database logic

* resolve PR

* fix lint issues

* resolve PR

* resolve PR

* resolve PR

* resolve PR

* update names

* resolve PR

* resolve PR

* fix lint error

* resolve PR

* resolve PR
2023-09-05 13:35:11 -07:00
Sean McManus 4199155228 Update TPN. (#11393) 2023-08-31 12:56:15 -07:00
Garrett Serack d949d93924 Apply strict eslint rule (#11389) 2023-08-31 09:26:55 -07:00
Marcin Strzyz 44e2a0ec4c added enforcement of no array constructor. (#11385) 2023-08-30 13:12:41 -07:00
Marcin Strzyz 0cd369c603 Incremental. (#11383) 2023-08-30 13:04:01 -07:00
Marcin Strzyz 76fce67276 Added typing guards. (#11382) 2023-08-29 18:05:33 -07:00
Marcin Strzyz f3e0f0bb05 Added enforcement. (#11381) 2023-08-29 16:54:14 -07:00
Garrett Serack 628301be37 Test restructuring and cleanup (#11262)
* updated files

* queue and ready are now separate

* checkpoint

* found it! fixed missing call

* cleaned up and refactored a bit

* cleanup

* whoops. make sure linter runs!

* Make the queue itself static

* addressed formatting issues, added more rules to eslint

* more formatting, made ready Promise/void

* checkpoint

* checkpoint

* checkpoint

* checkpoint (linting)

* checkpoint

* checkpoint

* checkpoint

* checkpoint

* renamed path to filepath.

* checkpoint

* checkpoint

* so close...

* checkpoint again

* before making doc

* checkpoint

* checkpoint

* Checkpoint

* renamed awaiters

* eslint

* fix format on generated native strings

* add dummy pretest task back in for the moment

* change unit test runing

* posix calc test failure

* make signal dispose better

* add 	est regen script

* missed file

* checkpoint

* Improve scripts a bit

* remove hooks for now

* remove unused script

* remove unused script

* filter out files

* ensure that eslint works for scripts too

* fix build oses to specific version

* cleanups and tweaking

* adjusted for cosmetic feedback

* more

* add eslint rule to fix space before/after semicolon

* remove tba/tbd

* cleanup

* Added space-infix-ops rule

* cleanup

* resolve comments

* resolve comments

* add simple debug task

* spelling fixes

* cleanup more

* More changes. yay

* remove the extra whitespace from before comments

* add eslint rule to ensure that there are never extra spaces

* adding another eslint rule to ensure that there isn't spacing around unary operators, which we all know is dangerous. Or weird. I forget which

* added a space between vs and code because a space is the desired format

* removed all mentions of transpiler which was removed

* removed an extra comma

* removed a trailing slash

* removed useless lines

* missed as file

* reconfigure no-extra-parens rule

* added note about yarn install

* whatever

* more fun

* FIx it so that it webpacks correctly

* remove refernces to attic

* restore line to correct check

* fix whitespace

* added blank yarn install

* removed
2023-08-29 16:08:07 -07:00
browntarik 6efaafef60 place markdownInComments setting under code doc (#11380) 2023-08-29 14:53:18 -07:00
Michelle Matias f387815749 Fix tag parse language status item UI (#11354) 2023-08-25 15:50:03 -07:00
Michelle Matias c873aa18bd 1.17.5 changelog (#11363) 2023-08-25 13:50:14 -07:00
Colen Garoutte-Carson 78a8ff3bb3 Disable AutoPCH early on platforms that don't support it (#11362) 2023-08-24 18:29:52 -07:00
Michelle Matias 3033657a19 Reset FAR UI if no results returned (#11359) 2023-08-23 18:03:44 -07:00
Sean McManus ac118f453b Fix formatting for IntelliSense loc strings. (#11348)
* Fix formatting for loc strings.
2023-08-22 15:04:23 -07:00
Sean McManus 9e10a71ffb Update changelog and version for 1.17.4 (#11340)
* Update changelog and version for 1.17.4
* Add a missed entry.
2023-08-21 11:08:15 -07:00
Sean McManus 4525bd0ed5 Fix crash called by missing IntelliSense loc strings. (#11339) 2023-08-21 10:40:35 -07:00
Garrett Serack 89d0a7a01f Enqueue the call to sendDidOpen (#11337)
* enqueue the call to sendDidOpen
2023-08-21 10:32:47 -07:00
Colen Garoutte-Carson 27cd52a1b9 Replace use of yauzl with node-stream-zip (#11304) 2023-08-17 18:42:56 -07:00
Colen Garoutte-Carson e020a75bb7 Merge branch 'release' into main 2023-08-16 17:55:19 -07:00
Colen Garoutte-Carson c8a7776222 Update version and changelog for 1.17.3 (#11330) 2023-08-16 17:50:39 -07:00
Bob Brown 3934ef89ea Fix bug introduced by #11175 (#11329) 2023-08-16 16:46:17 -07:00
285 changed files with 65405 additions and 49641 deletions
+3257 -95
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -32,7 +32,7 @@
"eslint-plugin-prettier": "^4.2.1",
"husky": "^8.0.1",
"mocha": "^10.0.0",
"mongodb": "^4.8.1",
"mongodb": "^4.17.0",
"nock": "^13.2.9",
"prettier": "2.7.1",
"ts-node": "^10.9.1",
+14 -47
View File
@@ -1,47 +1,14 @@
name: CI (Linux)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependencies
run: yarn install
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
uses: GabrielBB/[email protected]
with:
run: yarn run unitTests
working-directory: Extension
# - name: Run languageServer integration tests
# uses: GabrielBB/[email protected]
# with:
# run: yarn run integrationTests
# working-directory: Extension
name: CI (Linux)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: ubuntu-22.04
platform: linux
+15 -47
View File
@@ -1,47 +1,15 @@
name: CI (Mac)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependencies
run: yarn install --network-timeout 100000
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
uses: GabrielBB/[email protected]
with:
run: yarn run unitTests
working-directory: Extension
# - name: Run languageServer integration tests
# uses: GabrielBB/[email protected]
# with:
# run: yarn run integrationTests
# working-directory: Extension
name: CI (Mac)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: macos-12
platform: mac
yarn-args: --network-timeout 100000
+14 -43
View File
@@ -1,43 +1,14 @@
name: CI (Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
build:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependencies
run: yarn install
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Compile Test Sources
run: yarn run pretest
working-directory: Extension
- name: Run unit tests
run: yarn run unitTests
working-directory: Extension
# - name: Run languageServer integration tests
# run: yarn run integrationTests
# working-directory: Extension
name: CI (Windows)
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
jobs:
job:
uses: ./.github/workflows/job-compile-and-test.yml
with:
runner-env: windows-2022
platform: windows
@@ -0,0 +1,73 @@
# Reuable workflow for compiling and testing extension.
name: Compile and test extension
on:
workflow_call:
inputs:
runner-env:
required: true
type: string
platform:
# Expects 'mac', 'linux', or 'windows'
required: true
type: string
yarn-args:
type: string
jobs:
build:
runs-on: ${{ inputs.runner-env }}
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16
uses: actions/setup-node@v3
with:
node-version: 16
- name: Install Dependencies
run: yarn install ${{ inputs.yarn-args }}
working-directory: Extension
- name: Compile Sources
run: yarn run compile
working-directory: Extension
- name: Run Linter
run: yarn run lint
working-directory: Extension
- name: Run unit tests
run: yarn test
working-directory: Extension
# NOTE : We can't run the test that require the native binary files
# yet -- there will be an update soon that allows the tester to
# acquire them on-the-fly
# - name: Run languageServer integration tests
# if: ${{ inputs.platform == 'windows' }}
# run: yarn test --scenario=SingleRootProject
# working-directory: Extension
# - name: Run E2E IntelliSense features tests
# if: ${{ inputs.platform == 'windows' }}
# run: yarn test --scenario=MultirootDeadlockTest
# 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
# - name: Run languageServer integration tests (xvfb)
# if: ${{ inputs.platform == 'mac' || inputs.platform == 'linux' }}
# uses: coactions/setup-xvfb@v1
# with:
# run: yarn test --scenario=SingleRootProject
# 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=MultirootDeadlockTest
# working-directory: Extension
+3 -3
View File
@@ -19,7 +19,7 @@ parameters:
# Note: Make sure lldb_mi_commit is the same as the one in Extension/cgmanifest.json
# 'CommitHash' for lldb-mi.
lldb_mi_commit: 2388bd74133bc21eac59b2e2bf97f2a30770a315
lldb_mi_commit: 4fe9c663edce2447e114c71851694d8c529b982d
lldb_mi_additional_parameters: "-DUSE_LLDB_FRAMEWORK=1"
@@ -28,9 +28,9 @@ jobs:
timeoutInMinutes: 360
pool:
${{if eq(parameters['llvm_arch'], 'arm64')}}:
name: cpptoolsMacM1pool
vmImage: macos-13-arm64
${{ else }}:
vmImage: macOS-latest
vmImage: macOS-13
steps:
- task: CmdLine@2
displayName: 'Install Dependencies'
+2 -3
View File
@@ -1,5 +1,4 @@
*.js
test/**/index.ts
test/**/runTest.ts
tools/prepublish.js
dist/
vscode*.d.ts
+13 -3
View File
@@ -1,8 +1,8 @@
module.exports = {
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/eslint-recommended"
//"plugin:@typescript-eslint/strict", // I want to enable this. Lots of little changes will happen.
"plugin:@typescript-eslint/eslint-recommended",
"plugin:@typescript-eslint/strict",
],
"env": {
"browser": true,
@@ -11,7 +11,7 @@ module.exports = {
},
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": "tsconfig.json",
"project": ["tsconfig.json", ".scripts/tsconfig.json"],
"ecmaVersion": 2022,
"sourceType": "module",
"warnOnUnsupportedTypeScriptVersion": false,
@@ -59,11 +59,17 @@ module.exports = {
}
}
],
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/no-extraneous-class": "off",
"no-case-declarations": "off",
"no-useless-escape": "off",
"no-floating-decimal": "error",
"keyword-spacing": ["error", { "before": true, "overrides": { "this": { "before": false } } }],
"arrow-spacing": ["error", { "before": true, "after": true }],
"semi-spacing": ["error", { "before": false, "after": true }],
"no-extra-parens": ["error", "all", { "nestedBinaryExpressions": false, "ternaryOperandBinaryExpressions": false }],
"@typescript-eslint/no-array-constructor": "error",
"@typescript-eslint/no-useless-constructor": "error",
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
@@ -82,6 +88,7 @@ module.exports = {
"@typescript-eslint/unified-signatures": "error",
"@typescript-eslint/no-floating-promises": "error",
"@typescript-eslint/method-signature-style": ["error", "method"],
"@typescript-eslint/space-infix-ops": "error",
"no-unused-vars": "off",
"@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_" }],
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
@@ -110,16 +117,19 @@ module.exports = {
"no-fallthrough": "error",
"no-invalid-this": "error",
"no-irregular-whitespace": "error",
"rest-spread-spacing": ["error", "never"],
"no-multiple-empty-lines": ["error", { "max": 1, "maxEOF": 1, "maxBOF": 0 }],
"no-new-wrappers": "error",
"no-return-await": "error",
"no-sequences": "error",
"no-sparse-arrays": "error",
"no-trailing-spaces": "error",
"no-multi-spaces": "error",
"no-undef-init": "error",
"no-unsafe-finally": "error",
"no-unused-expressions": "error",
"no-unused-labels": "error",
"space-before-blocks": "error",
"no-var": "error",
"one-var": [
"error",
+1
View File
@@ -34,3 +34,4 @@ localized_string_ids.h
src/nativeStrings.ts
vscode*.d.ts
.scripts/_*
+64
View File
@@ -0,0 +1,64 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { error } from 'node:console';
import { resolve, sep } from 'node:path';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { verbose } from '../src/Utility/Text/streams';
import { $root, Git, brightGreen, cyan, getModifiedIgnoredFiles, rimraf } from './common';
// notes:
// list all gitignore'd files that are modified: `git clean -Xd -n`
// list all untracked and ignored files that are modified/created: `git clean -Xd -n`
export async function main() {
await rimraf(resolve($root, 'dist'));
}
export async function all() {
await rimraf(...(await getModifiedIgnoredFiles()).filter(each => !each.includes('node_modules')));
}
export async function reset() {
verbose(`Resetting all .gitignored files in extension`);
await rimraf(...await getModifiedIgnoredFiles());
}
async function details(files: string[]) {
let all = await Promise.all(files.filter(each => each).map(async (each) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const [filename, stats ] = await filepath.stats(each);
return {
filename: stats.isDirectory() ? cyan(`${each}${sep}**`) : brightGreen(`${each}`),
date: stats.mtime.toLocaleDateString().replace(/\b(\d)\//g, '0$1\/'),
time: stats.mtime.toLocaleTimeString().replace(/^(\d)\:/g, '0$1:'),
modified: stats.mtime
};
}));
all = all.sort((a, b) => a.modified.getTime() - b.modified.getTime());
// print a formatted table so the date and time are aligned
const max = all.reduce((max, each) => Math.max(max, each.filename.length), 0);
all.forEach(each => console.log(` ${each.filename.padEnd(max)} [${each.date} ${each.time}]`));
console.log('');
}
export async function show(opt?: string) {
switch (opt?.toLowerCase()) {
case 'new':
console.log(cyan('\n\nNew files:'));
const r = await Git('ls-files', '--others', '--exclude-standard', '-z');
return details(r.stdio.all().map(each => resolve(each.trim().replace(/\0/g, ''))));
case undefined:
case '':
case 'ignored':
case 'untracked':
console.log(cyan('\n\nUntracked+Ignored files:'));
return details(await getModifiedIgnoredFiles());
default:
return error(`Unknown option '${opt}'`);
}
}
+40
View File
@@ -0,0 +1,40 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { spawnSync } from 'child_process';
import { verbose } from '../src/Utility/Text/streams';
import { $args, $root, $scenario, assertAnyFile, brightGreen, gray, green, pwd } from './common';
import { resolve } from 'path';
import { getTestInfo } from '../test/common/selectTests';
import { install, options } from "./vscode";
export { install, reset } from './vscode';
export async function main() {
let ti = await getTestInfo($scenario);
if (!ti) {
// try using the first arg as a scenario name or location
ti = await getTestInfo($args[0], $args[0] ? resolve(pwd, $args[0]) : undefined);
if (ti) {
$args[0] = ti.workspace;
}
} else {
// we found it
$args.unshift(ti.workspace);
}
await assertAnyFile('dist/src/main.js', `The extension entry point '${$root}/dist/src/main.js is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const { cli, args } = await install();
// example of installing an extension into code
//verbose(`Installing release version of 'ms-vscode.cpptools'`);
//spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cpptools'], { encoding: 'utf-8', stdio: 'ignore' })
verbose(green('Launch VSCode'));
const ARGS = [...args, ...options.launchArgs.filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir=')), `--extensionDevelopmentPath=${$root}`, ...$args ];
verbose(gray(`${cli}\n ${ [...ARGS ].join('\n ')}`));
spawnSync(cli, ARGS, { encoding: 'utf-8', stdio: 'ignore', env: { ...process.env, DONT_PROMPT_WSL_INSTALL:"1" } });
}
+343
View File
@@ -0,0 +1,343 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { Command, CommandFunction } from '../src/Utility/Process/program';
import { ok } from 'assert';
import { CommentJSONValue, parse, stringify } from 'comment-json';
import { mkdir as md, readFile, rm, writeFile } from 'fs/promises';
import { IOptions, glob as globSync } from 'glob';
import { dirname, resolve } from 'path';
import { chdir, cwd, env } from 'process';
import { setImmediate } from 'timers/promises';
import { promisify } from 'util';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { is } from '../src/Utility/System/guards';
import { verbose } from '../src/Utility/Text/streams';
export const $root = resolve(`${__dirname}/..`);
export let $cmd = 'main';
export let $scenario = '';
// loop through the args and pick out --scenario=... and remove it from the $args and set $scenario
process.argv.slice(2).filter(each => !(each.startsWith('--scenario=') && ($scenario = each.substring('--scenario='.length))));
export const $args = process.argv.slice(2).filter(each => !each.startsWith('--'));
export const $switches = process.argv.slice(2).filter(each => each.startsWith('--'));
/** enqueue the call to the callback function to happen on the next available tick, and return a promise to the result */
export function then<T>(callback: () => Promise<T> | T): Promise<T> {
return setImmediate().then(callback);
}
export const pwd = env.INIT_CWD ?? cwd();
verbose(yellow(`pwd: ${pwd}`));
// ensure we're in the extension folder.
chdir($root);
// dump unhandled async errors to the console and exit.
process.on('unhandledRejection', (reason: any, _promise) => {
error(`${reason?.stack?.split(/\r?\n/).filter(l => !l.includes('node:internal') && !l.includes('node_modules')).join('\n')}`);
process.exit(1);
});
const git = new Command('git');
export const Git = async (...args: Parameters<Awaited<CommandFunction>>) => (await git)(...args);
export const GitClean = async (...args: Parameters<Awaited<CommandFunction>>) => (await new Command(await git, 'clean'))(...args);
export async function getModifiedIgnoredFiles() {
const {code, error, stdio } = await GitClean('-Xd', '-n');
if (code) {
throw new Error(`\n${error.all().join('\n')}`);
}
// return the full path of files that would be removed.
return Promise.all(stdio.filter("Would remove").map((s) => filepath.exists(s.replace(/^Would remove /, ''), $root)).filter(p => p));
}
export async function rimraf(...paths: string[]) {
const all = [];
for (const each of paths) {
if (!each) {
continue;
}
if (await filepath.isFolder(each)) {
verbose(`Removing folder ${red(each)}`);
all.push(rm(each, {recursive: true, force: true}));
continue;
}
verbose(`Removing file ${red(each)}`);
all.push(rm(each, {force: true}));
}
await Promise.all(all);
}
export async function mkdir(filePath: string) {
const [fullPath, info] = await filepath.stats(filePath, $root);
if (info) {
if (info.isDirectory()) {
return fullPath;
}
throw new Error(`Cannot create directory '${filePath}' because there is a file there.`);
}
await md(fullPath, { recursive: true });
return fullPath;
}
export const glob: (pattern: string, options?: IOptions) => Promise<string[]> = promisify(globSync);
export async function write(filePath: string, data: Buffer | string) {
await mkdir(dirname(filePath));
if (await filepath.isFile(filePath)) {
const content = await readFile(filePath);
if (is.string(data)) {
// if we're passed a text file, we should match the line endings of the existing file.
const textContent = content.toString();
// normalize the line endings to the same as the current file.
data = textContent.indexOf('\r\n') > -1 ? data.replace(/\r\n|\n/g, '\r\n') : data.replace(/\r\n|\n/g, '\n');
// if the text content is a match, we don't have to change anything
if (textContent === data) {
verbose(`Text file at '${filePath}' is up to date.`);
return;
}
} else {
// if the binary content is a match, we don't have to change anything
if (content.equals(data)) {
verbose(`File at '${filePath}' is up to date.`);
return;
}
}
}
verbose(`Writing file '${filePath}'`);
await writeFile(filePath, data);
}
export async function updateFiles(files: string[], dest: string | Promise<string>) {
const target = is.promise(dest) ? await dest : dest;
await Promise.all(files.map(async (each) => {
const sourceFile = await filepath.isFile(each, $root);
if (sourceFile) {
const targetFile = resolve(target, each);
await write(targetFile, await readFile(sourceFile));
}
}));
}
export async function go() {
if (require.main) {
// loop through the args and pick out the first non --arg and remove it from the $args and set $cmd
for (let i = 0; i < $args.length; i++) {
const each = $args[i];
if (!each.startsWith('--') && require.main.exports[each]) {
$cmd = each;
$args.splice(i, 1);
break;
}
}
verbose(`${yellow("Running task:")} ${green($cmd)} ${green($args.join(' '))}`);
require.main.exports[$cmd](...$args);
}
}
void then(go);
export async function read(filename: string) {
const content = await readFile(filename);
ok(content, `File '${filename}' has no content`);
return content.toString();
}
export async function readJson(filename: string, fallback = {}): Promise<CommentJSONValue> {
try {
return parse(await read(filename));
} catch {
return fallback as CommentJSONValue;
}
}
export async function writeJson(filename: string, object: CommentJSONValue) {
await write(filename, stringify(object, null, 4));
}
export function error(text: string) {
console.error(`\n${red('ERROR')}: ${text}`);
return true;
}
export function warn(text: string) {
console.error(`\n${yellow('WARNING')}: ${text}`);
return true;
}
export function note(text: string) {
console.error(`\n${cyan('NOTE')}: ${text}`);
}
export function underline(text: string) {
return `\u001b[4m${text}\u001b[0m`;
}
export function bold(text: string) {
return `\u001b[1m${text}\u001b[0m`;
}
export function dim(text: string) {
return `\u001b[2m${text}\u001b[0m`;
}
export function brightGreen(text: string) {
return `\u001b[38;2;19;161;14m${text}\u001b[0m`;
}
export function green(text: string) {
return `\u001b[38;2;78;154;6m${text}\u001b[0m`;
}
export function brightWhite(text: string) {
return `\u001b[38;2;238;238;236m${text}\u001b[0m`;
}
export function gray(text: string) {
return `\u001b[38;2;117;113;94m${text}\u001b[0m`;
}
export function yellow(text: string) {
return `\u001b[38;2;252;233;79m${text}\u001b[0m`;
}
export function red(text: string) {
return `\u001b[38;2;197;15;31m${text}\u001b[0m`;
}
export function cyan(text: string) {
return `\u001b[38;2;0;174;239m${text}\u001b[0m`;
}
export const hr = "===============================================================================";
export function heading(text: string, level = 1) {
switch (level) {
case 1:
return `${underline(bold(text))}`;
case 2:
return `${brightGreen(text)}`;
case 3:
return `${green(text)}`;
}
return `${bold(text)}\n`;
}
export function optional(text: string) {
return gray(text);
}
export function cmdSwitch(text: string) {
return optional(`--${text}`);
}
export function command(text: string) {
return brightWhite(bold(text));
}
export function hint(text: string) {
return green(dim(text));
}
export function count(num: number) {
return gray(`${num}`);
}
export function position(text: string) {
return gray(`${text}`);
}
export async function assertAnyFolder(oneOrMoreFolders: string | string[], errorMessage?: string): Promise<string> {
oneOrMoreFolders = is.array(oneOrMoreFolders) ? oneOrMoreFolders : [oneOrMoreFolders];
for (const each of oneOrMoreFolders) {
const result = await filepath.isFolder(each, $root);
if (result) {
verbose(`Folder ${brightGreen(each)} exists.`);
return result;
}
}
if (errorMessage) {
if (!$switches.includes('--quiet')) {
error(errorMessage);
}
process.exit(1);
}
}
export async function assertAnyFile(oneOrMoreFiles: string | string[], errorMessage?: string): Promise<string> {
oneOrMoreFiles = is.array(oneOrMoreFiles) ? oneOrMoreFiles : [oneOrMoreFiles];
for (const each of oneOrMoreFiles) {
const result = await filepath.isFile(each, $root);
if (result) {
verbose(`Folder ${brightGreen(each)} exists.`);
return result;
}
}
if (errorMessage) {
if (!$switches.includes('--quiet')) {
error(errorMessage);
}
process.exit(1);
}
}
const quiet = process.argv.includes('--quiet');
export async function checkPrep() {
let failing = false;
failing = !await assertAnyFolder('dist/test') && (quiet || warn(`The compiled test files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/walkthrough') && (quiet || warn(`The walkthrough files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/html') && (quiet || warn(`The html files are not in place.`)) || failing;
failing = !await assertAnyFolder('dist/schema') && (quiet || warn(`The schema files are not in place.`)) || failing;
failing = !await assertAnyFile('dist/nls.metadata.json') && (quiet || warn(`The extension translation file '${$root}/dist/nls.metadata.json is missing.`)) || failing;
failing = await checkDTS() || failing;
if (!failing) {
verbose('Prep files appear to be in place.');
}
return failing;
}
export async function checkCompiled() {
let failing = false;
failing = await checkDTS() || failing;
failing = !await assertAnyFile('dist/src/main.js') && (quiet || warn(`The extension entry point '${$root}/dist/src/main.js is missing.`)) || failing;
if (!failing) {
verbose('Compiled files appear to be in place.');
}
return failing;
}
export async function checkDTS() {
let failing = false;
failing = !await assertAnyFile('vscode.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.d.ts is missing.`)) || failing;
failing = !await assertAnyFile('vscode.proposed.terminalDataWriteEvent.d.ts') && (quiet || warn(`The VSCode import file '${$root}/dist/src/vscode.proposed.terminalDataWriteEvent.d.ts is missing.`)) || failing;
if (!failing) {
verbose('VSCode d.ts files appear to be in place.');
}
return failing;
}
export async function checkBinaries() {
let failing = false;
failing = !await assertAnyFile(['bin/cpptools.exe', 'bin/cpptools']) && (quiet || warn(`The native binary files are not present. You should either build or install the native binaries\n\n.`)) || failing;
if (!failing) {
verbose('Native binary files appear to be in place.');
}
return failing;
}
+28
View File
@@ -0,0 +1,28 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { watch as watchFiles } from 'fs/promises';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { verbose } from '../src/Utility/Text/streams';
import { $root, glob, mkdir, updateFiles } from './common';
export async function main() {
verbose(`Copying walkthrough media to extension/dist folder`);
await updateFiles(await glob('walkthrough/images/**/*'), mkdir('dist'));
}
export async function watch() {
const source = await filepath.isFolder('walkthrough/images', $root);
if (source) {
verbose(`Watching ${source} folder for changes.`);
console.log('Press Ctrl+C to exit.');
// eslint-disable-next-line @typescript-eslint/no-unused-vars
for await (const event of watchFiles(source, {recursive: true })) {
await main();
}
}
}
+134
View File
@@ -0,0 +1,134 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { parse } from 'comment-json';
import { resolve } from 'path';
import { read, write } from './common';
// ****************************
// Command: generate-native-strings
// The following is used to generate nativeStrings.ts and localized_string_ids.h from ./src/nativeStrings.json
// If adding localized strings to the native side, start by adding it to nativeStrings.json and use this to generate the others.
// ****************************
export async function main() {
const $root = resolve(`${__dirname}/..`);
const stringTable = parse(await read(`${$root}/src/nativeStrings.json`)) as any;
let nativeEnumContent = "";
let nativeStringTableContent = "";
let typeScriptSwitchContent = "";
let stringIndex = 1;
for (const property in stringTable) {
let stringValue = stringTable[property];
let hintValue;
if (typeof stringValue !== "string") {
hintValue = stringValue.hint;
stringValue = stringValue.text;
}
// Add to native enum
nativeEnumContent += ` ${property} = ${stringIndex},\n`;
// Add to native string table
nativeStringTableContent += ` ${JSON.stringify(stringValue)},\n`;
// Add to TypeScript switch
// Skip empty strings, which can be used to prevent enum/index reordering
if (stringValue !== "") {
// It's possible that a translation may skip "{#}" entries, so check for up to 50 of them.
let numArgs = 0;
for (let i = 0; i < 50; i++) {
if (stringValue.includes(`{${i}}`)) {
numArgs = i + 1;
}
}
typeScriptSwitchContent += ` case ${stringIndex}:\n`;
if (numArgs !== 0) {
typeScriptSwitchContent += ` if (stringArgs) {\n`;
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
for (let i = 0; i < numArgs; i++) {
typeScriptSwitchContent += `, stringArgs[${i}]`;
}
typeScriptSwitchContent += `);\n break;\n }\n`;
}
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
typeScriptSwitchContent += `);\n break;\n`;
}
++stringIndex;
}
// --------------------------------------------------------------------------------------------
// Generate the TypeScript file
// --------------------------------------------------------------------------------------------
const typeScriptContent = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
'use strict';
import * as nls from 'vscode-nls';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export const localizedStringCount: number = ${stringIndex};
export function lookupString(stringId: number, stringArgs?: string[]): string {
let message: string = "";
switch (stringId) {
case 0:
// Special case for blank string
break;
${typeScriptSwitchContent}
default:
console.assert(\"Unrecognized string ID\");
break;
}
return message;
}
`;
// If the file isn't there, or the contents are different, write it out
await write(`${$root}/src/nativeStrings.ts`, typeScriptContent);
// --------------------------------------------------------------------------------------------
// Generate the native string header file
// --------------------------------------------------------------------------------------------
const nativeContents = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
#pragma once
// NOLINTBEGIN(modernize-raw-string-literal)
enum class localized_string_id : unsigned int
{
blank = 0,
${nativeEnumContent}};
inline static const char *localizable_strings[] = {
"",
${nativeStringTableContent}};
// NOLINTEND(modernize-raw-string-literal)
`;
// If the file isn't there, or the contents are different, write it out
await write(`${$root}/localized_string_ids.h`, nativeContents);
}
@@ -5,8 +5,8 @@
/* eslint-disable no-prototype-builtins */
import * as fs from 'fs';
import * as os from 'os';
import { resolve } from 'path';
import { $root, read, write } from './common';
function appendFieldsToObject(reference: any, obj: any): any {
// Make sure it is an object type
@@ -56,7 +56,7 @@ function updateDefaults(object: any, defaults: any): any {
function refReplace(definitions: any, ref: any): any {
// $ref is formatted as "#/definitions/ObjectName"
const referenceStringArray: string[] = ref['$ref'].split('/');
const referenceStringArray: string[] = ref.$ref.split('/');
// Getting "ObjectName"
const referenceName: string = referenceStringArray[referenceStringArray.length - 1];
@@ -71,7 +71,7 @@ function refReplace(definitions: any, ref: any): any {
ref = appendFieldsToObject(reference, ref);
// Remove $ref field
delete ref['$ref'];
delete ref.$ref;
return ref;
}
@@ -116,10 +116,10 @@ function mergeReferences(baseDefinitions: any, additionalDefinitions: any): void
}
}
function generateOptionsSchema(): void {
const packageJSON: any = JSON.parse(fs.readFileSync('package.json').toString());
const schemaJSON: any = JSON.parse(fs.readFileSync('tools/OptionsSchema.json').toString());
const symbolSettingsJSON: any = JSON.parse(fs.readFileSync('tools/VSSymbolSettings.json').toString());
export async function main() {
const packageJSON: any = JSON.parse(await read(resolve($root, 'package.json')));
const schemaJSON: any = JSON.parse(await read(resolve($root, 'tools/OptionsSchema.json')));
const symbolSettingsJSON: any = JSON.parse(await read(resolve($root, 'tools/VSSymbolSettings.json')));
mergeReferences(schemaJSON.definitions, symbolSettingsJSON.definitions);
@@ -135,15 +135,10 @@ function generateOptionsSchema(): void {
packageJSON.contributes.debuggers[1].configurationAttributes.attach = schemaJSON.definitions.CppvsdbgAttachOptions;
let content: string = JSON.stringify(packageJSON, null, 4);
if (os.platform() === 'win32') {
content = content.replace(/\n/gm, "\r\n");
}
// We use '\u200b' (unicode zero-length space character) to break VS Code's URL detection regex for URLs that are examples. This process will
// convert that from the readable espace sequence, to just an invisible character. Convert it back to the visible espace sequence.
content = content.replace(/\u200b/gm, "\\u200b");
content = content.replace(/\u200b/gm, "\\u200b") + "\n";
fs.writeFileSync('package.json', content);
await write('package.json', content);
}
generateOptionsSchema();
+95
View File
@@ -0,0 +1,95 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as fs from "fs";
import * as path from 'path';
import { parseString } from 'xml2js';
import { mkdir, write } from './common';
export async function main() {
const localizeRepoPath = process.argv[2];
const cpptoolsRepoPath = process.argv[3];
if (!localizeRepoPath || !cpptoolsRepoPath) {
console.error(`ERROR: Usage: ${path.parse(process.argv[0]).base} ${path.parse(process.argv[1]).base} <Localize repo path> <vscode-cpptools repo path>`);
return;
}
console.log("Importing EDGE strings from Localize repo: " + localizeRepoPath);
console.log("Writing to cpptools repo: " + cpptoolsRepoPath);
if (!fs.existsSync(path.join(localizeRepoPath, ".git"))) {
console.error("ERROR: Localize repo submodule is not initialized in Localize repo");
return;
}
const languages = [
{ id: "zh-tw", folderName: "cht", transifexId: "zh-hant" },
{ id: "zh-cn", folderName: "chs", transifexId: "zh-hans" },
{ id: "fr", folderName: "fra" },
{ id: "de", folderName: "deu" },
{ id: "it", folderName: "ita" },
{ id: "es", folderName: "esn" },
{ id: "ja", folderName: "jpn" },
{ id: "ko", folderName: "kor" },
{ id: "ru", folderName: "rus" },
{ id: "bg", folderName: "bul" }, // VS Code supports Bulgarian, but VS is not currently localized for those languages.
{ id: "hu", folderName: "hun" }, // VS Code supports Hungarian, but VS is not currently localized for those languages.
{ id: "pt-br", folderName: "ptb", transifexId: "pt-BR" },
{ id: "tr", folderName: "trk" },
{ id: "cs", folderName: "csy" },
{ id: "pl", folderName: "plk" }
];
const locFolderNames = fs.readdirSync(localizeRepoPath).filter(f => fs.lstatSync(path.join(localizeRepoPath, f)).isDirectory());
for (const locFolderName of locFolderNames) {
const lclPath = path.join(localizeRepoPath, locFolderName, "vc/vc/cpfeui.dll.lcl");
const languageInfo = languages.find(l => l.folderName === locFolderName);
if (!languageInfo) {
return;
}
const languageId = languageInfo.id;
const outputLanguageFolder = path.join(cpptoolsRepoPath, "Extension/bin/messages", languageId);
const outputPath = path.join(outputLanguageFolder, "messages.json");
const sourceContent = fs.readFileSync(lclPath, 'utf-8');
// Scan once, just to determine how many there are the size of the array we need
let highestValue = 0;
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId === ";String Table") {
item.Item.forEach((subItem) => {
const itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
const resultArray = new Array(highestValue);
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId === ";String Table") {
item.Item.forEach((subItem) => {
const itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
resultArray[itemId] = subItem.Str[0].Tgt[0].Val[0].replace(/\]5D;/g, "]");
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
await mkdir(outputLanguageFolder);
await write(outputPath, JSON.stringify(resultArray, null, 4) + "\n");
}
}
+17
View File
@@ -0,0 +1,17 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { gray, green, readJson } from './common';
export async function main() {
const pkg = await readJson('package.json') as Record<string, any>;
if (pkg.scripts) {
console.log(green('\n\nAvailable script commands:\n'));
for (const key of Object.keys(pkg.scripts)) {
console.log(green(`yarn ${key} - ${gray(pkg.scripts[key])}`));
}
console.log('');
}
}
+236
View File
@@ -0,0 +1,236 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { runTests } from '@vscode/test-electron';
import { spawnSync } from 'child_process';
import { CommentArray, CommentObject } from 'comment-json';
import { readdir } from 'fs/promises';
import { resolve } from 'path';
import { env } from 'process';
import { returns } from '../src/Utility/Async/returns';
import { filepath } from '../src/Utility/Filesystem/filepath';
import { is } from '../src/Utility/System/guards';
import { verbose } from '../src/Utility/Text/streams';
import { getTestInfo } from '../test/common/selectTests';
import { $args, $root, $scenario, assertAnyFile, assertAnyFolder, brightGreen, checkBinaries, cmdSwitch, cyan, error, gray, green, readJson, red, writeJson } from './common';
import { install, isolated, options } from './vscode';
export { install, reset } from './vscode';
const sowrite = process.stdout.write.bind(process.stdout) as (...args: unknown[]) => boolean;
const sewrite = process.stderr.write.bind(process.stderr) as (...args: unknown[]) => boolean;
const filters = [
/^\[(.*)\].*/,
/^Unexpected token A/,
/Cannot register 'cmake.cmakePath'/,
/\[DEP0005\] DeprecationWarning/,
/--trace-deprecation/,
/Iconv-lite warning/,
/^Extension '/,
/^Found existing install/
];
// remove unwanted messages from stdio
function filterStdio() {
process.stdout.write = function (...args: unknown[]) {
if (typeof args[0] === 'string') {
const text = args[0];
if (filters.some(each => text.match(each))) {
return true;
}
}
if (args[0] instanceof Buffer) {
const text = args[0].toString();
if (filters.some(each => text.match(each))) {
return true;
}
}
return sowrite(...args);
};
process.stderr.write = function (...args: unknown[]) {
if (typeof args[0] === 'string') {
const text = args[0];
if (filters.some(each => text.match(each))) {
return true;
}
}
if (args[0] instanceof Buffer) {
const text = args[0].toString();
if (filters.some(each => text.match(each))) {
return true;
}
}
return sewrite(...args);
};
}
filterStdio();
async function unitTests() {
await assertAnyFolder('dist/test/unit', `The folder '${$root}/dist/test/unit is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const mocha = await assertAnyFile(["node_modules/.bin/mocha.cmd", "node_modules/.bin/mocha"], `Can't find the mocha testrunner. You might need to run ${brightGreen("yarn install")}\n\n`);
const result = spawnSync(mocha, [`${$root}/dist/test/unit/**/*.test.js`, '--timeout', '30000'], { stdio:'inherit'});
verbose(`\n${green("NOTE:")} If you want to run a scenario test (end-to-end) use ${cmdSwitch('scenario=<NAME>')} \n\n`);
return result.status;
}
async function scenarioTests(assets: string, name: string, workspace: string) {
if (await checkBinaries()) {
process.exit(1);
}
return runTests({
...options,
extensionDevelopmentPath: $root,
extensionTestsPath: resolve($root, 'dist/test/common/selectTests'),
launchArgs: workspace ? [...options.launchArgs, workspace] : options.launchArgs,
extensionTestsEnv: {
SCENARIO: assets
}
});
}
export async function main() {
await assertAnyFolder('dist/test/', `The folder '${$root}/dist/test is missing. You should run ${brightGreen("yarn compile")}\n\n`);
const arg = $args.find(each => !each.startsWith("--"));
const specifiedScenario = $scenario || env.SCENARIO || await getScenarioFolder(arg);
const testInfo = await getTestInfo(specifiedScenario);
if (!testInfo) {
if (arg) {
return error(`Could not find scenario ${arg}`);
}
// lets just run the unit tests
process.exit(await unitTests());
}
// at this point, we're going to run some vscode tests
if (!await filepath.isFolder(isolated)) {
await install();
}
process.exit(await scenarioTests(testInfo.assets, testInfo.name, testInfo.workspace));
}
export async function all() {
if (await checkBinaries()) {
process.exit(1);
}
const finished: string[] = [];
if (await unitTests() !== 0) {
console.log(`${cyan(" UNIT TESTS: ")}${red("failed")}`);
process.exit(1);
}
finished.push(`${cyan(" UNIT TESTS: ")}${green("success")}`);
// at this point, we're going to run some vscode tests
if (!await filepath.isFolder(isolated)) {
await install();
}
try {
const scenarios = await getScenarioNames();
for (const each of scenarios) {
if (await filepath.isFolder(`${$root}/test/scenarios/${each}/tests`)) {
const ti = await getTestInfo(each);
if (ti) {
console.log(`\n\nRunning scenario ${each}`);
const result = await scenarioTests(ti.assets, ti.name, ti.workspace);
if (result) {
console.log(finished.join('\n'));
console.log(` ${cyan(`${ti.name} Tests:`)}${red("failed")}`);
process.exit(result);
}
finished.push(` ${cyan(`${ti.name} Tests:`)}${green("success")}`);
}
}
}
} catch (e) {
error(e);
} finally {
console.log(finished.join('\n'));
}
}
interface Input {
id: string;
type: string;
description: string;
options: CommentArray<{label: string; value: string}>;
}
export async function getScenarioNames() {
return (await readdir(`${$root}/test/scenarios`).catch(returns.none)).filter(each => each !== 'Debugger');
}
export async function getScenarioFolder(scenarioName: string) {
return scenarioName ? resolve(`${$root}/test/scenarios/${(await getScenarioNames()).find(each => each.toLowerCase() === scenarioName.toLowerCase())}`) : undefined;
}
export async function list() {
console.log(`\n${cyan("Scenarios: ")}\n`);
const names = await getScenarioNames();
const max = names.reduce((max, each) => Math.max(max, each), 0);
for (const each of names) {
console.log(` ${green(each.padEnd(max))}: ${gray(await getScenarioFolder(each))}`);
}
}
export async function regen() {
// update the .vscode/launch.json file with the scenarios
const scenarios = await getScenarioNames();
const launch = await readJson(`${$root}/.vscode/launch.json`) as CommentObject;
if (!is.object(launch)) {
return error(`The file ${$root}/.vscode/launch.json is not valid json`);
}
if (!is.array(launch.inputs)) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'inputs' array`);
}
const inputs = launch.inputs as unknown as CommentArray<Input>;
const pickScenario = inputs.find(each => each.id === 'pickScenario');
if (!pickScenario) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'pickScenario' input`);
}
const pickWorkspace = inputs.find(each => each.id === 'pickWorkspace');
if (!pickWorkspace) {
return error(`The file ${$root}/.vscode/launch.json is missing the 'pickWorkspace' input`);
}
for (const scenarioFolder of scenarios) {
const prefix = $root.replace(/\\/g, '/');
if (await filepath.isFolder(`${$root}/test/scenarios/${scenarioFolder}/tests`)) {
const testInfo = await getTestInfo(scenarioFolder);
if (testInfo) {
const label = `${scenarioFolder} `;
const value = testInfo.workspace.replace(/\\/g, '/').replace(prefix, '${workspaceFolder}');
const scenario = pickScenario.options.find(s => s.label === label);
if (!scenario) {
console.log(`Adding scenario ${green(scenarioFolder)} to pickScenario`);
pickScenario.options.push({ label, value });
} else {
verbose(`Skipping scenario ${scenarioFolder} because it already exists`);
}
const wrkspace = pickWorkspace.options.find(s => s.label === label);
if (!wrkspace) {
console.log(`Adding workspace ${green(scenarioFolder)} to pickWorkspace`);
pickWorkspace.options.push({ label, value });
} else {
verbose(`Skipping workspace ${scenarioFolder} because it already exists`);
}
} else {
verbose(`Skipping scenario ${scenarioFolder} because it doesn't look like there are any tests. (maybe try and run ${brightGreen("yarn compile")})`);
}
}
}
await writeJson(`${$root}/.vscode/launch.json`, launch);
}
+12
View File
@@ -0,0 +1,12 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "node16",
"moduleResolution": "node16",
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"esModuleInterop": true
}
}
+52
View File
@@ -0,0 +1,52 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { checkBinaries, checkCompiled, checkDTS, checkPrep, error, green } from './common';
const quiet = process.argv.includes('--quiet');
export async function main() {
let failing = await checkPrep() && (quiet || error(`Files are not up to date. Run ${green('yarn prep')} to fix it.`));
failing = (await checkCompiled() && (quiet || error(`Compiled files are not present. Run ${green('yarn compile')} to fix it.`))) || failing;
failing = (await checkBinaries() && (quiet || error(`The native binary files are not present. You should either build or install the native binaries\n\n.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function compiled() {
let failing = false;
failing = (await checkCompiled() && (quiet || error(`Compiled files are not present. Run ${green('yarn compile')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function binaries() {
let failing = false;
failing = (await checkBinaries() && (quiet || error(`The native binary files are not present. You should either build or install the native binaries\n\n.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function prep() {
let failing = false;
failing = (await checkPrep() && (quiet || error(`Files are not up to date. Run ${green('yarn prep')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
export async function dts() {
let failing = false;
failing = (await checkDTS() && (quiet || error(`VSCode import files are not present. Run ${green('yarn prep')} to fix it.`))) || failing;
if (failing) {
process.exit(1);
}
}
+61
View File
@@ -0,0 +1,61 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath } from '@vscode/test-electron';
import { createHash } from 'crypto';
import { tmpdir } from 'os';
import { resolve } from 'path';
import { verbose } from '../src/Utility/Text/streams';
import { mkdir, readJson, rimraf, write } from './common';
export const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(__dirname).digest('hex').substring(0, 6));
export const extensionsDir = resolve(isolated, 'extensions');
export const userDir = resolve(isolated, 'user-data');
export const settings = resolve(userDir, "User", 'settings.json');
export const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${extensionsDir}`, `--user-data-dir=${userDir}`, '--disable-workspace-trust']
};
export async function install() {
try {
// Create a new isolated directory for VS Code instance in the test folder, and make it specific to the extension folder so we can avoid collisions.
// keeping this out of the Extension folder means we're not worried about VS Code getting weird with locking files and such.
verbose(`Isolated VSCode test folder: ${isolated}`);
await mkdir(isolated);
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...args] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
args.push(`--extensions-dir=${extensionsDir}`, `--user-data-dir=${userDir}`);
// install the appropriate extensions
// spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cpptools'], { encoding: 'utf-8', stdio: 'ignore' });
// spawnSync(cli, [...args, '--install-extension', 'twxs.cmake'], { encoding: 'utf-8', stdio: 'ignore' });
// spawnSync(cli, [...args, '--install-extension', 'ms-vscode.cmake-tools'], { encoding: 'utf-8', stdio: 'ignore' });
const settingsJson = await readJson(settings, {});
if (!settingsJson["workbench.colorTheme"]) {
settingsJson["workbench.colorTheme"] = "Tomorrow Night Blue";
}
settingsJson["git.openRepositoryInParentFolders"] = "never";
await write(settings, JSON.stringify(settingsJson, null, 4));
return {
cli, args
};
} catch (err: unknown) {
console.log(err);
}
}
export async function reset() {
verbose(`Removing VSCode test folder: ${isolated}`);
await rimraf(isolated);
}
+102 -102
View File
@@ -3,128 +3,75 @@
"version": "0.1.0",
"configurations": [
{
"name": "Launch Extension (development)",
// debugs the extension
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev",
},
{
"name": "Launch Extension (production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile",
},
{
"name": "Launch Extension (do not build)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
},
{
"name": "Launch Extension (watch, development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev Watch",
},
{
"name": "Launch Extension (watch, production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile Watch",
},
{
"name": "Launch Unit Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-workspace-trust",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/unitTests/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
"${workspaceFolder}/dist/**"
],
"preLaunchTask": "Pretest"
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
"name": "Launch Integration Tests",
// debugs the extension (selecting the workspace)
"name": "Run Extension-Select Workspace",
"type": "extensionHost",
"request": "launch",
"args": [
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-workspace-trust",
"--extensionDevelopmentPath=${workspaceFolder}",
"${input:pickWorkspace}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**"
],
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
// debug scenario tests (selecting the workspace)
"name": "VSCode Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"env": {
"SCENARIO": "${input:pickScenario}"
},
"args": [
"${workspaceFolder}/test/integrationTests/testAssets/SimpleCppProject/simpleCppProject.code-workspace",
"--no-sandbox",
"--disable-updates",
"--skip-welcome",
"--skip-release-notes",
"--disable-extensions",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/languageServer/index"
"--extensionTestsPath=${workspaceFolder}/dist/test/common/selectTests",
"--scenario=${input:pickScenario}",
"${input:pickScenario}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
"${workspaceFolder}/dist/**"
],
"preLaunchTask": "Pretest",
},
{
"name": "Launch E2E IntelliSense features tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/../../Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/IntelliSenseFeatures/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Node Attach",
"type": "node",
"request": "attach",
"port": 5858
// you can use a watch task as a prelaunch task and it works like you'd want it to.
"preLaunchTask": "watch"
},
{
// used for debugging unit tests
"name": "MochaTest",
"type": "node",
"request": "attach",
@@ -135,9 +82,62 @@
"<node_internals>/**"
],
"outFiles": [
"${workspaceFolder}/**/out/**/*.js",
"${workspaceFolder}/dist/**",
"!**/node_modules/**"
]
}
],
"inputs": [
{
"type": "pickString",
"id": "pickScenario",
"description": "Select which scenario to debug VSCode tests.",
"options": [
{
"label": "MultirootDeadlockTest ",
"value": "${workspaceFolder}/test/scenarios/MultirootDeadlockTest/assets/test.code-workspace"
},
{
"label": "SimpleCppProject ",
"value": "${workspaceFolder}/test/scenarios/SimpleCppProject/assets/simpleCppProject.code-workspace"
},
{
"label": "SingleRootProject ",
"value": "${workspaceFolder}/test/scenarios/SingleRootProject/assets/"
},
{
"label": "CompilerDetection ",
"value": "${workspaceFolder}/test/scenarios/CompilerDetection/assets"
}
]
},
{
"type": "pickString",
"id": "pickWorkspace",
"description": "Select which workspace scenario to debug VSCode.",
"default": "-n",
"options": [
{
"label": "(Debug with new window) ",
"value": "-n"
},
{
"label": "MultirootDeadlockTest ",
"value": "${workspaceFolder}/test/scenarios/MultirootDeadlockTest/assets/test.code-workspace"
},
{
"label": "SimpleCppProject ",
"value": "${workspaceFolder}/test/scenarios/SimpleCppProject/assets/simpleCppProject.code-workspace"
},
{
"label": "SingleRootProject ",
"value": "${workspaceFolder}/test/scenarios/SingleRootProject/assets/"
},
{
"label": "CompilerDetection ",
"value": "${workspaceFolder}/test/scenarios/CompilerDetection/assets"
}
]
}
]
}
+18 -3
View File
@@ -9,8 +9,8 @@
"typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
// if you install the mocha test explorer extension, you can run the unit tests from the test explorer UI
"testExplorer.useNativeTesting": true,
"mochaExplorer.files": "./**/internalUnitTests/**/*.test.js",
"mochaExplorer.watch": "./**/internalUnitTests/**/*.test.js",
"mochaExplorer.files": "./**/unit/**/*.test.js",
"mochaExplorer.watch": "./**/unit/**/*.test.js",
"mochaExplorer.ignore": [
"**/*skip*",
"**/dist/test/**/*.d.ts",
@@ -48,5 +48,20 @@
"eslint.format.enable": true,
"[javascript]": {
"editor.tabSize": 4,
}
},
"markdown.extension.list.indentationSize": "inherit",
"markdown.extension.toc.levels": "2..6",
"[markdown]": {
"editor.tabSize": 4,
},
"eslint.workingDirectories": [
{
"changeProcessCWD": true,
"directory": "./",
},
{
"changeProcessCWD": true,
"directory": "./.scripts",
}
],
}
+15 -193
View File
@@ -4,203 +4,25 @@
"version": "2.0.0",
"tasks": [
{
"label": "TypeScript Compile",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": false,
"type": "shell",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared"
},
"command": "yarn",
"args": [
"run",
"compile"
]
},
{
"label": "TypeScript Lint",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"lint"
],
"problemMatcher": {
"fileLocation": "absolute",
"source": "lint",
"pattern": [
{
"regexp": "(ERROR:) ([a-zA-Z/:\\-\\.]*)\\[(\\d+), (\\d+)\\]: (.*)",
"severity": 1,
"file": 2,
"line": 3,
"column": 4,
"message": 5
}
]
},
"dependsOn": [
"Compile Dev"
]
},
{
"label": "Compile Dev",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"compile-dev"
]
},
{
"label": "Pretest",
"group": "build",
"isBackground": false,
"type": "shell",
"command": "yarn",
"args": [
"run",
"pretest"
],
"dependsOn": [
"Compile Dev"
]
},
{
"label": "TypeScript Compile Watch",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": true,
"type": "shell",
"presentation": {
"echo": true,
"reveal": "silent",
"focus": false,
"panel": "shared"
},
"command": "yarn",
"args": [
"run",
"compile-watch"
],
"problemMatcher": [
{
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
"file": 1,
"line": 2,
"column": 3
},
{
"regexp": "\\s*TS\\d+:\\s*(.*)",
"message": 1
}
],
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "asset"
},
"endsPattern": {
"regexp": "webpack (.*?) compiled (.*?) ms"
}
}
}
]
},
{
"label": "Compile Dev Watch",
"group": "build",
"isBackground": true,
"type": "shell",
"command": "yarn",
"args": [
"run",
"compile-dev-watch"
],
"problemMatcher": [
{
"owner": "typescript",
"source": "ts",
"applyTo": "closedDocuments",
"fileLocation": "absolute",
"severity": "error",
"pattern": [
{
"regexp": "\\[tsl\\] ERROR in (.*)?\\((\\d+),(\\d+)\\)",
"file": 1,
"line": 2,
"column": 3
},
{
"regexp": "\\s*TS\\d+:\\s*(.*)",
"message": 1
}
],
"background": {
"activeOnStart": true,
"beginsPattern": {
"regexp": "asset"
},
"endsPattern": {
"regexp": "webpack (.*?) compiled (.*?) ms"
}
}
}
]
},
{
"label": "Compile:Watch (unit-tests)",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}"
},
"command": "yarn",
"args": [
"run",
"compile-watch-unit-tests"
],
"isBackground": true,
"problemMatcher": "$tsc-watch",
"group": {
"kind": "build",
"isDefault": false
}
},
{
"label": "Compile (unit-tests)",
"type": "shell",
"options": {
"cwd": "${workspaceFolder}"
},
"command": "yarn",
"args": [
"run",
"compile-unit-tests"
],
"label": "compile",
"type": "npm",
"script": "compile",
"problemMatcher": "$tsc",
"group": {
"kind": "build",
"isDefault": false
"isDefault": true
}
},
{
"label": "watch",
"type": "npm",
"script": "watch",
"group": {
"kind": "build",
"isDefault": true
},
"isBackground": true,
"problemMatcher": "$tsc-watch",
}
]
}
+54 -47
View File
@@ -1,47 +1,54 @@
# ignore vscode settings for extension development
.vscode/**
# ignore binaries
obj/**
# ignore source files
tools/**
notices/**
test/**
src/**
# ignore .js files that are webpacked or only used for development
out/src/**
out/tools/**
# ignore ts files in ui
ui/*.ts
# ignore Azure-Pipelines files
jobs/**
cgmanifest.json
# ignore development files
tsconfig.json
test.tsconfig.json
tslint.json
.eslintrc.js
webpack.config.js
tscCompileList.txt
gulpfile.js
.gitattributes
.gitignore
CMakeLists.txt
debugAdapters/install.lock*
typings/**
**/*.map
import_edge_strings.js
localized_string_ids.h
translations_auto_pr.js
# ignore i18n language files
i18n/**
# ignore node_modules
node_modules/
# ignore vscode settings for extension development
.vscode/**
# ignore binaries
obj/**
# ignore source files
tools/**
notices/**
test/**
src/**
# ignore .js files that are webpacked or only used for development
out/src/**
out/tools/**
# don't include the local code and tests compiled files
dist/test/**
# no project scripts
.scripts/**
# ignore ts files in ui
ui/*.ts
# ignore Azure-Pipelines files
jobs/**
cgmanifest.json
# ignore development files
tsconfig.json
test.tsconfig.json
ui.tsconfig.json
tslint.json
.eslintrc.js
webpack.config.js
tscCompileList.txt
gulpfile.js
.gitattributes
.gitignore
CMakeLists.txt
debugAdapters/install.lock*
typings/**
**/*.map
import_edge_strings.js
localized_string_ids.h
translations_auto_pr.js
# ignore i18n language files
i18n/**
# ignore node_modules
node_modules/
+7
View File
@@ -0,0 +1,7 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
ignore-engines true
disable-self-update-check true
--run.silent true
+39
View File
@@ -1,5 +1,43 @@
# C/C++ for Visual Studio Code Changelog
## Version 1.18.0: October 12, 2023
### New Features
* Add an 'Extract to Function' (or Member Function) code action after selecting code. [#1162](https://github.com/microsoft/vscode-cpptools/issues/1162)
* Currently, it's only enabled when `C_Cpp.experimentFeatures` is `true`. Also, 'Extract to Free Function' is disabled.
* Compiler acquisition improvements. [#10525](https://github.com/microsoft/vscode-cpptools/issues/10525)
### Enhancements
* Add setting `C_Cpp.refactoring.includeHeader` to customize whether or not to add an include header when doing a refactoring code action. [#11271](https://github.com/microsoft/vscode-cpptools/issues/11271)
* Update clang-format and clang-tidy to 17.0.2. [PR #11491](https://github.com/microsoft/vscode-cpptools/pull/11491)
### Bug Fixes
* Fix the debugger truncating long strings when inspecting values. [#1786](https://github.com/microsoft/vscode-cpptools/issues/1786)
* Switch to using `XDG_CACHE_HOME` on Linux for the default database path. [#10191](https://github.com/microsoft/vscode-cpptools/issues/10191)
* Fix incorrect status and commands with the tag parsing language status UI. [#10749](https://github.com/microsoft/vscode-cpptools/issues/10749)
* Fix an empty (`""`) `compilerPath` in a base configuration overriding the compiler specified by a custom configuration provider or a `compile_commands.json`. [#11373](https://github.com/microsoft/vscode-cpptools/issues/11373)
* Fix a startup crash when reading values from JSON (settings) that are not the type expected. [#11375](https://github.com/microsoft/vscode-cpptools/issues/11375)
* Fix a crash detected by crash telemetry. [#11401](https://github.com/microsoft/vscode-cpptools/issues/11401)
* Fix handling of an undefined `env` variable on Linux and macOS. [#11447](https://github.com/microsoft/vscode-cpptools/issues/11447)
* Fix multiple issues with querying `nvcc` (CUDA) as a compiler. [#11454](https://github.com/microsoft/vscode-cpptools/issues/11454)
* Fix an issue that could cause a C language standard to be applied to a C++ file, or vice versa.
* Remove `cpp` and `clang-cpp` preprocessors from the list of detectable compilers.
## Version 1.17.5: August 28, 2023
### Bug Fixes
* Fix a language server crash for platforms that don't support the IntelliSense cache (AutoPCH). [#10789](https://github.com/microsoft/vscode-cpptools/issues/10789)
* Fix markdown in comments when inline/block code is used. [#11322](https://github.com/microsoft/vscode-cpptools/issues/11322)
* Fix Find All References and Call Hierarchy for C files when the cursor is at the end of a symbol. [#11338](https://github.com/microsoft/vscode-cpptools/issues/11338)
* Fix usage of the `/Zc:alignedNew-` MSVC compiler option. [#11350](https://github.com/microsoft/vscode-cpptools/issues/11350)
## Version 1.17.4: August 21, 2023
### Bug Fixes
* Fix crash recovery for the main extension process. [#11335](https://github.com/microsoft/vscode-cpptools/issues/11335)
* Fix an IntelliSense process crash when certain error messages occur with a language pack enabled. [#11336](https://github.com/microsoft/vscode-cpptools/issues/11336)
## Version 1.17.3: August 16, 2023
### Bug Fix
* Fix a regression with attaching the debugger to processes on Linux and macOS. [#11328](https://github.com/microsoft/vscode-cpptools/issues/11328)
## Version 1.17.2: August 14, 2023
### Enhancements
* Enable a subset of markdown to render in hover by default and a `C_Cpp.markdownInComments` setting. [#6020](https://github.com/microsoft/vscode-cpptools/issues/6020), [#10461](https://github.com/microsoft/vscode-cpptools/issues/10461)
@@ -14,6 +52,7 @@
* Fix an issue where the debugger would get stuck while using cl.exe options. [#10231](https://github.com/microsoft/vscode-cpptools/issues/10231)
* Fix C/C++ commands showing in the Command Palette with non-C/C++ files. [#10421](https://github.com/microsoft/vscode-cpptools/issues/10421)
* Fix the 'Select IntelliSense Configuration' command to also update an existing `compilerPath` in c_cpp_properties.json. [#10808](https://github.com/microsoft/vscode-cpptools/issues/10808)
* Update clang-format (and clang-tidy) to 16.0.6 to fix a bug. [#11027](https://github.com/microsoft/vscode-cpptools/issues/11027)
* Fix `#include` completion leaving an extra `>`. [#11042](https://github.com/microsoft/vscode-cpptools/issues/11042)
* Fix an issue with matching of glob patterns containing path delimiters. [#11132](https://github.com/microsoft/vscode-cpptools/issues/11132)
* Fix Create Declaration/Definition via `Quick Fix…` from hover tooltip. [#11157](https://github.com/microsoft/vscode-cpptools/issues/11157)
+124 -129
View File
@@ -17,7 +17,7 @@ required to debug changes to any libraries licensed under the GNU Lesser General
---------------------------------------------------------
lldb-tools/lldb-mi 2388bd74133bc21eac59b2e2bf97f2a30770a315 - Apache-2.0 WITH LLVM-exception
lldb-tools/lldb-mi 4fe9c663edce2447e114c71851694d8c529b982d - Apache-2.0 WITH LLVM-exception
Copyright (c) 2010 Apple Inc.
@@ -1419,36 +1419,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
buffer-crc32 0.2.13 - MIT
https://github.com/brianloveswords/buffer-crc32
Copyright (c) 2013 Brian J. Brennan
The MIT License
Copyright (c) 2013 Brian J. Brennan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -1677,38 +1647,6 @@ The above copyright notice and this permission notice shall be included in all c
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
fd-slicer 1.1.0 - MIT
https://github.com/andrewrk/node-fd-slicer#readme
Copyright (c) 2014 Andrew Kelley
Copyright (c) 2014 Andrew Kelley
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -2072,6 +2010,37 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
nanoid 3.3.6 - MIT
https://github.com/ai/nanoid#readme
Copyright 2017 Andrey Sitnik <[email protected]>
The MIT License (MIT)
Copyright 2017 Andrey Sitnik <[email protected]>
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -2102,6 +2071,63 @@ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
node-stream-zip 1.15.0 - MIT
https://github.com/antelle/node-stream-zip
Copyright (c) 2021 Antelle https://github.com/antelle
(c) 2020 Antelle https://github.com/antelle/node-stream-zip/blob/master/LICENSE
Copyright (c) 2012 Another-D-Mention Software and other contributors, http://www.another-d-mention.ro
Portions copyright https://github.com/cthackers/adm-zip https://raw.githubusercontent.com/cthackers/adm-zip/master/LICENSE
Copyright (c) 2021 Antelle https://github.com/antelle
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
== dependency license: adm-zip ==
Copyright (c) 2012 Another-D-Mention Software and other contributors,
http://www.another-d-mention.ro/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -2168,40 +2194,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
pend 1.2.0 - MIT
Copyright (c) 2014 Andrew Kelley
The MIT License (Expat)
Copyright (c) 2014 Andrew Kelley
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation files
(the "Software"), to deal in the Software without restriction,
including without limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of the Software,
and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -2235,6 +2227,41 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
plist 3.1.0 - MIT
https://github.com/TooTallNate/node-plist#readme
Copyright (c) 2010-2017 Nathan Rajlich <[email protected]>
(The MIT License)
Copyright (c) 2010-2017 Nathan Rajlich <[email protected]>
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
@@ -2636,38 +2663,6 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
---------------------------------------------------------
---------------------------------------------------------
yauzl 2.10.0 - MIT
https://github.com/thejoshwolfe/yauzl
Copyright (c) 2014 Josh Wolfe
The MIT License (MIT)
Copyright (c) 2014 Josh Wolfe
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
---------------------------------------------------------
-------------------------------------------------------------------
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -16,7 +16,7 @@
"Type": "git",
"Git": {
"RepositoryUrl": "https://github.com/lldb-tools/lldb-mi",
"CommitHash": "2388bd74133bc21eac59b2e2bf97f2a30770a315"
"CommitHash": "4fe9c663edce2447e114c71851694d8c529b982d"
}
}
}
+1 -138
View File
@@ -6,7 +6,7 @@
'use strict';
const gulp = require('gulp');
const eslint = require('gulp-eslint-new');
const fs = require('fs');
const nls = require('vscode-nls-dev');
const path = require('path');
@@ -58,24 +58,6 @@ const languages = [
{ id: "pl", folderName: "plk" }
];
/// Misc Tasks
const allTypeScript = [
'src/**/*.ts',
'!**/*.d.ts',
'!**/typings**'
];
gulp.task('lint', function () {
return gulp.src(allTypeScript)
.pipe(eslint({ overrideConfigFile: ".eslintrc.js" }))
.pipe(eslint.format())
.pipe(eslint.failAfterError());
});
gulp.task('copy-walkthrough-media', function () {
return gulp.src('walkthrough/images/**/*')
.pipe(gulp.dest('dist/walkthrough/images'));
});
// ****************************
// Command: translations-export
@@ -462,122 +444,3 @@ const generateJsonSchemaLoc = () => {
gulp.task('translations-generate', gulp.series(generateSrcLocBundle, generateAdditionalLocFiles, generateHtmlLoc, generateWalkthroughHtmlLoc, generateJsonSchemaLoc));
// ****************************
// Command: generate-native-strings
// The following is used to generate nativeStrings.ts and localized_string_ids.h from ./src/nativeStrings.json
// If adding localized strings to the native side, start by adding it to nativeStrings.json and use this to generate the others.
// ****************************
// A gulp task to parse ./src/nativeStrings.json and generate nativeStrings.ts, and localized_string_ids.h
gulp.task("generate-native-strings", (done) => {
const stringTable = jsonc.parse(fs.readFileSync('./src/nativeStrings.json').toString());
let nativeEnumContent = ""
let nativeStringTableContent = "";
let typeScriptSwitchContent = "";
let stringIndex = 1;
for (let property in stringTable) {
let stringValue = stringTable[property];
let hintValue;
if (typeof stringValue !== "string") {
hintValue = stringValue.hint;
stringValue = stringValue.text;
}
// Add to native enum
nativeEnumContent += ` ${property} = ${stringIndex},\n`;
// Add to native string table
nativeStringTableContent += ` ${JSON.stringify(stringValue)},\n`;
// Add to TypeScript switch
// Skip empty strings, which can be used to prevent enum/index reordering
if (stringValue != "") {
// It's possible that a translation may skip "{#}" entries, so check for up to 50 of them.
let numArgs = 0;
for (let i = 0; i < 50; i++) {
if (stringValue.includes(`{${i}}`)) {
numArgs = i + 1;
}
}
typeScriptSwitchContent += ` case ${stringIndex}:\n`;
if (numArgs != 0) {
typeScriptSwitchContent += ` if (stringArgs) {\n`;
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
for (let i = 0; i < numArgs; i++) {
typeScriptSwitchContent += `, stringArgs[${i}]`;
}
typeScriptSwitchContent += `);\n break;\n }\n`;
}
if (hintValue) {
typeScriptSwitchContent += ` message = localize({ key: ${JSON.stringify(property)}, comment: [${JSON.stringify(hintValue)}] }, ${JSON.stringify(stringValue)}`;
} else {
typeScriptSwitchContent += ` message = localize(${JSON.stringify(property)}, ${JSON.stringify(stringValue)}`;
}
typeScriptSwitchContent += `);\n break;\n`;
}
++stringIndex;
};
let typeScriptContent = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
'use strict';
import * as nls from 'vscode-nls';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export const localizedStringCount: number = ${stringIndex};
export function lookupString(stringId: number, stringArgs?: string[]): string {
let message: string = "";
switch (stringId) {
case 0:
// Special case for blank string
break;
${typeScriptSwitchContent}
default:
console.assert(\"Unrecognized string ID\");
break;
}
return message;
}
`;
console.log("Writing file: ./src/nativeStrings.ts");
fs.writeFileSync("./src/nativeStrings.ts", typeScriptContent, 'utf8');
let nativeContents = `/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
// ****** This file is generated from nativeStrings.json. Do not edit this file directly. ******
#pragma once
// NOLINTBEGIN(modernize-raw-string-literal)
enum class localized_string_id : unsigned int
{
blank = 0,
${nativeEnumContent}};
inline static const char *localizable_strings[] = {
"",
${nativeStringTableContent}};
// NOLINTEND(modernize-raw-string-literal)
`;
console.log("Writing file: localized_string_ids.h -- If changed, copy to VS repo: src/vc/designtime/vscode/Common/generated/");
fs.writeFileSync("localized_string_ids.h", nativeContents, 'utf8');
done();
});
-89
View File
@@ -1,89 +0,0 @@
'use strict';
const fs = require('fs');
const path = require('path');
const parseString = require('xml2js').parseString;
let localizeRepoPath = process.argv[2];
let cpptoolsRepoPath = process.argv[3];
if (!localizeRepoPath || !cpptoolsRepoPath) {
console.error(`ERROR: Usage: ${path.parse(process.argv[0]).base} ${path.parse(process.argv[1]).base} <Localize repo path> <vscode-cpptools repo path>`);
return;
}
console.log("Importing EDGE strings from Localize repo: " + localizeRepoPath);
console.log("Writing to cpptools repo: " + cpptoolsRepoPath);
if (!fs.existsSync(path.join(localizeRepoPath, ".git"))) {
console.error("ERROR: Localize repo submodule is not initialized in Localize repo");
return;
}
const languages = [
{ id: "zh-tw", folderName: "cht", transifexId: "zh-hant" },
{ id: "zh-cn", folderName: "chs", transifexId: "zh-hans" },
{ id: "fr", folderName: "fra" },
{ id: "de", folderName: "deu" },
{ id: "it", folderName: "ita" },
{ id: "es", folderName: "esn" },
{ id: "ja", folderName: "jpn" },
{ id: "ko", folderName: "kor" },
{ id: "ru", folderName: "rus" },
{ id: "bg", folderName: "bul" }, // VS Code supports Bulgarian, but VS is not currently localized for those languages.
{ id: "hu", folderName: "hun" }, // VS Code supports Hungarian, but VS is not currently localized for those languages.
{ id: "pt-br", folderName: "ptb", transifexId: "pt-BR" },
{ id: "tr", folderName: "trk" },
{ id: "cs", folderName: "csy" },
{ id: "pl", folderName: "plk" }
];
var locFolderNames = fs.readdirSync(localizeRepoPath).filter(f => fs.lstatSync(path.join(localizeRepoPath, f)).isDirectory());
locFolderNames.forEach((locFolderName) => {
let lclPath = path.join(localizeRepoPath, locFolderName, "vc/vc/cpfeui.dll.lcl");
let languageInfo = languages.find(l => l.folderName == locFolderName);
if (!languageInfo) {
return;
}
let languageId = languageInfo.id;
let outputLanguageFolder = path.join(cpptoolsRepoPath, "Extension/bin/messages", languageId);
let outputPath = path.join(outputLanguageFolder, "messages.json");
let sourceContent = fs.readFileSync(lclPath, 'utf-8');
// Scan once, just to determine how many there are the size of the array we need
let highestValue = 0;
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId == ";String Table") {
item.Item.forEach((subItem) => {
let itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
let resultArray = new Array(highestValue);
parseString(sourceContent, function (err, result) {
result.LCX.Item.forEach((item) => {
if (item.$.ItemId == ";String Table") {
item.Item.forEach((subItem) => {
let itemId = parseInt(subItem.$.ItemId, 10);
if (subItem.Str[0].Tgt) {
resultArray[itemId] = subItem.Str[0].Tgt[0].Val[0].replace(/\]5D;/g, "]");
if (highestValue < itemId) {
highestValue = itemId;
}
}
});
}
});
});
fs.mkdirSync(outputLanguageFolder, { recursive: true });
fs.writeFileSync(outputPath, JSON.stringify(resultArray, null, 2), 'utf8');
});
+220 -57
View File
@@ -2,7 +2,7 @@
"name": "cpptools",
"displayName": "C/C++",
"description": "C/C++ IntelliSense, debugging, and code browsing.",
"version": "1.17.2-main",
"version": "1.18.0-main",
"publisher": "ms-vscode",
"icon": "LanguageCCPP_color_128x.png",
"readme": "README.md",
@@ -58,7 +58,7 @@
"workspaceContains:/.vscode/c_cpp_properties.json",
"onFileSystem:cpptools-schema"
],
"main": "./dist/main",
"main": "./dist/src/main",
"contributes": {
"walkthroughs": [
{
@@ -88,11 +88,29 @@
"id": "awaiting.activation.windows",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.activating.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == false",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == false && cpptools.windowsVersion != 10 && cpptools.windowsVersion != 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows.md"
}
},
{
"id": "awaiting.activation.windows10",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.activating.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == false && cpptools.windowsVersion == 10",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows10.md"
}
},
{
"id": "awaiting.activation.windows11",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.activating.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == false && cpptools.windowsVersion == 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows11.md"
}
},
{
"id": "no.compilers.found.mac",
"title": "%c_cpp.walkthrough.set.up.title%",
@@ -114,12 +132,30 @@
{
"id": "no.compilers.found.windows",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.no.compilers.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == true",
"description": "%c_cpp.walkthrough.no.compilers.windows.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == true && cpptools.windowsVersion != 10 && cpptools.windowsVersion != 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows.md"
}
},
{
"id": "no.compilers.found.windows10",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.no.compilers.windows.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == true && cpptools.windowsVersion == 10",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows10.md"
}
},
{
"id": "no.compilers.found.windows11",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.no.compilers.windows.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == true && cpptools.windowsVersion == 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows11.md"
}
},
{
"id": "verify.compiler.mac",
"title": "%c_cpp.walkthrough.set.up.title%",
@@ -148,7 +184,7 @@
"id": "verify.compiler.windows",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.compilers.found.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == false",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == false && cpptools.windowsVersion != 10 && cpptools.windowsVersion != 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows.md"
},
@@ -156,6 +192,30 @@
"onContext:cpptools.trustedCompilerFound"
]
},
{
"id": "verify.compiler.windows10",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.compilers.found.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == false && cpptools.windowsVersion == 10",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows10.md"
},
"completionEvents": [
"onContext:cpptools.trustedCompilerFound"
]
},
{
"id": "verify.compiler.windows11",
"title": "%c_cpp.walkthrough.set.up.title%",
"description": "%c_cpp.walkthrough.compilers.found.description%",
"when": "workspacePlatform == windows && cpptools.scanForCompilersDone == true && cpptools.scanForCompilersEmpty == false && cpptools.windowsVersion == 11",
"media": {
"markdown": "dist/walkthrough/installcompiler/install-compiler-windows11.md"
},
"completionEvents": [
"onContext:cpptools.trustedCompilerFound"
]
},
{
"id": "create.cpp.file",
"title": "%c_cpp.walkthrough.create.cpp.file.title%",
@@ -456,22 +516,6 @@
],
"scope": "resource"
},
"C_Cpp.markdownInComments": {
"type": "string",
"enum": [
"subsetEnabled",
"enabled",
"disabled"
],
"enumDescriptions": [
"%c_cpp.configuration.markdownInComments.subsetEnabled.description%",
"%c_cpp.configuration.markdownInComments.enabled.description%",
"%c_cpp.configuration.markdownInComments.disabled.description%"
],
"default": "subsetEnabled",
"description": "%c_cpp.configuration.markdownInComments.description%",
"scope": "resource"
},
"C_Cpp.hover": {
"type": "string",
"enum": [
@@ -517,6 +561,22 @@
"description": "%c_cpp.configuration.inactiveRegionBackgroundColor.description%",
"scope": "resource"
},
"C_Cpp.refactoring.includeHeader": {
"type": "string",
"enum": [
"always",
"ifNeeded",
"never"
],
"default": "always",
"markdownDescription": "%c_cpp.configuration.refactoring.includeHeader.markdownDescription%",
"enumDescriptions": [
"%c_cpp.configuration.refactoring.includeHeader.always.description%",
"%c_cpp.configuration.refactoring.includeHeader.ifNeeded.description%",
"%c_cpp.configuration.refactoring.includeHeader.never.description%"
],
"scope": "resource"
},
"C_Cpp.renameRequiresIdentifier": {
"type": "boolean",
"default": true,
@@ -1492,6 +1552,22 @@
"description": "%c_cpp.configuration.commentContinuationPatterns.description%",
"scope": "window"
},
"C_Cpp.markdownInComments": {
"type": "string",
"enum": [
"subsetEnabled",
"enabled",
"disabled"
],
"enumDescriptions": [
"%c_cpp.configuration.markdownInComments.subsetEnabled.description%",
"%c_cpp.configuration.markdownInComments.enabled.description%",
"%c_cpp.configuration.markdownInComments.disabled.description%"
],
"default": "subsetEnabled",
"description": "%c_cpp.configuration.markdownInComments.description%",
"scope": "resource"
},
"C_Cpp.simplifyStructuredComments": {
"type": "boolean",
"default": true,
@@ -1713,6 +1789,7 @@
"bugprone-dangling-handle",
"bugprone-dynamic-static-initializers",
"bugprone-easily-swappable-parameters",
"bugprone-empty-catch",
"bugprone-exception-escape",
"bugprone-fold-init-type",
"bugprone-forward-declaration-namespace",
@@ -1730,9 +1807,12 @@
"bugprone-misplaced-pointer-arithmetic-in-alloc",
"bugprone-misplaced-widening-cast",
"bugprone-move-forwarding-reference",
"bugprone-multiple-*",
"bugprone-multiple-new-in-one-expression",
"bugprone-multiple-statement-macro",
"bugprone-narrowing-conversions",
"bugprone-no-escape",
"bugprone-non-zero-enum-to-bool-conversion",
"bugprone-not-null-terminated-result",
"bugprone-parent-virtual-call",
"bugprone-posix-return",
@@ -1761,6 +1841,7 @@
"bugprone-suspicious-semicolon",
"bugprone-suspicious-string-compare",
"bugprone-swapped-arguments",
"bugprone-switch-missing-default-case",
"bugprone-terminating-continue",
"bugprone-throw-keyword-missing",
"bugprone-too-small-loop-variable",
@@ -1770,6 +1851,7 @@
"bugprone-unhandled-*",
"bugprone-unhandled-exception-at-new",
"bugprone-unhandled-self-assignment",
"bugprone-unique-ptr-array-mismatch",
"bugprone-unused-raii",
"bugprone-unused-return-value",
"bugprone-use-after-move",
@@ -1929,6 +2011,7 @@
"cppcoreguidelines-*",
"cppcoreguidelines-avoid-*",
"cppcoreguidelines-avoid-c-arrays",
"cppcoreguidelines-avoid-capturing-lambda-coroutines",
"cppcoreguidelines-avoid-const-or-ref-data-members",
"cppcoreguidelines-avoid-do-while",
"cppcoreguidelines-avoid-goto",
@@ -1941,6 +2024,8 @@
"cppcoreguidelines-interfaces-global-init",
"cppcoreguidelines-macro-to-enum",
"cppcoreguidelines-macro-usage",
"cppcoreguidelines-misleading-capture-default-by-value",
"cppcoreguidelines-missing-std-forward",
"cppcoreguidelines-narrowing-conversions",
"cppcoreguidelines-no-malloc",
"cppcoreguidelines-non-private-member-variables-in-classes",
@@ -1958,6 +2043,7 @@
"cppcoreguidelines-pro-type-static-cast-downcast",
"cppcoreguidelines-pro-type-union-access",
"cppcoreguidelines-pro-type-vararg",
"cppcoreguidelines-rvalue-reference-param-not-moved",
"cppcoreguidelines-slicing",
"cppcoreguidelines-special-member-functions",
"cppcoreguidelines-virtual-class-destructor",
@@ -2048,11 +2134,14 @@
"llvmlibc-*",
"llvmlibc-callee-namespace",
"llvmlibc-implementation-in-namespace",
"llvmlibc-inline-function-decl",
"llvmlibc-restrict-system-libc-headers",
"misc-*",
"misc-confusable-identifiers",
"misc-const-correctness",
"misc-definitions-in-headers",
"misc-header-include-cycle",
"misc-include-cleaner",
"misc-misleading-*",
"misc-misleading-bidirectional",
"misc-misleading-identifier",
@@ -2094,6 +2183,7 @@
"modernize-replace-random-shuffle",
"modernize-return-braced-init-list",
"modernize-shrink-to-fit",
"modernize-type-traits",
"modernize-unary-static-assert",
"modernize-use-*",
"modernize-use-auto",
@@ -2108,6 +2198,7 @@
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",
"modernize-use-std-print",
"modernize-use-trailing-return-type",
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
@@ -2129,6 +2220,7 @@
"openmp-exception-escape",
"openmp-use-default-none",
"performance-*",
"performance-avoid-endl",
"performance-faster-string-find",
"performance-for-range-copy",
"performance-implicit-conversion-in-loop",
@@ -2142,7 +2234,10 @@
"performance-no-*",
"performance-no-automatic-move",
"performance-no-int-to-ptr",
"performance-noexcept-*",
"performance-noexcept-destructor",
"performance-noexcept-move-constructor",
"performance-noexcept-swap",
"performance-trivially-destructible",
"performance-type-promotion-in-math-fn",
"performance-unnecessary-*",
@@ -2153,7 +2248,9 @@
"portability-simd-intrinsics",
"portability-std-allocator-const",
"readability-*",
"readability-avoid-*",
"readability-avoid-const-params-in-decls",
"readability-avoid-unconditional-preprocessor-if",
"readability-braces-around-statements",
"readability-const-return-type",
"readability-container-*",
@@ -2179,6 +2276,7 @@
"readability-misplaced-array-index",
"readability-named-parameter",
"readability-non-const-parameter",
"readability-operators-representation",
"readability-qualified-auto",
"readability-redundant-*",
"readability-redundant-access-specifiers",
@@ -2277,6 +2375,7 @@
"bugprone-dangling-handle",
"bugprone-dynamic-static-initializers",
"bugprone-easily-swappable-parameters",
"bugprone-empty-catch",
"bugprone-exception-escape",
"bugprone-fold-init-type",
"bugprone-forward-declaration-namespace",
@@ -2294,9 +2393,12 @@
"bugprone-misplaced-pointer-arithmetic-in-alloc",
"bugprone-misplaced-widening-cast",
"bugprone-move-forwarding-reference",
"bugprone-multiple-*",
"bugprone-multiple-new-in-one-expression",
"bugprone-multiple-statement-macro",
"bugprone-narrowing-conversions",
"bugprone-no-escape",
"bugprone-non-zero-enum-to-bool-conversion",
"bugprone-not-null-terminated-result",
"bugprone-parent-virtual-call",
"bugprone-posix-return",
@@ -2325,6 +2427,7 @@
"bugprone-suspicious-semicolon",
"bugprone-suspicious-string-compare",
"bugprone-swapped-arguments",
"bugprone-switch-missing-default-case",
"bugprone-terminating-continue",
"bugprone-throw-keyword-missing",
"bugprone-too-small-loop-variable",
@@ -2334,6 +2437,7 @@
"bugprone-unhandled-*",
"bugprone-unhandled-exception-at-new",
"bugprone-unhandled-self-assignment",
"bugprone-unique-ptr-array-mismatch",
"bugprone-unused-raii",
"bugprone-unused-return-value",
"bugprone-use-after-move",
@@ -2493,6 +2597,7 @@
"cppcoreguidelines-*",
"cppcoreguidelines-avoid-*",
"cppcoreguidelines-avoid-c-arrays",
"cppcoreguidelines-avoid-capturing-lambda-coroutines",
"cppcoreguidelines-avoid-const-or-ref-data-members",
"cppcoreguidelines-avoid-do-while",
"cppcoreguidelines-avoid-goto",
@@ -2505,6 +2610,8 @@
"cppcoreguidelines-interfaces-global-init",
"cppcoreguidelines-macro-to-enum",
"cppcoreguidelines-macro-usage",
"cppcoreguidelines-misleading-capture-default-by-value",
"cppcoreguidelines-missing-std-forward",
"cppcoreguidelines-narrowing-conversions",
"cppcoreguidelines-no-malloc",
"cppcoreguidelines-non-private-member-variables-in-classes",
@@ -2522,6 +2629,7 @@
"cppcoreguidelines-pro-type-static-cast-downcast",
"cppcoreguidelines-pro-type-union-access",
"cppcoreguidelines-pro-type-vararg",
"cppcoreguidelines-rvalue-reference-param-not-moved",
"cppcoreguidelines-slicing",
"cppcoreguidelines-special-member-functions",
"cppcoreguidelines-virtual-class-destructor",
@@ -2612,11 +2720,14 @@
"llvmlibc-*",
"llvmlibc-callee-namespace",
"llvmlibc-implementation-in-namespace",
"llvmlibc-inline-function-decl",
"llvmlibc-restrict-system-libc-headers",
"misc-*",
"misc-confusable-identifiers",
"misc-const-correctness",
"misc-definitions-in-headers",
"misc-header-include-cycle",
"misc-include-cleaner",
"misc-misleading-*",
"misc-misleading-bidirectional",
"misc-misleading-identifier",
@@ -2658,6 +2769,7 @@
"modernize-replace-random-shuffle",
"modernize-return-braced-init-list",
"modernize-shrink-to-fit",
"modernize-type-traits",
"modernize-unary-static-assert",
"modernize-use-*",
"modernize-use-auto",
@@ -2672,6 +2784,7 @@
"modernize-use-noexcept",
"modernize-use-nullptr",
"modernize-use-override",
"modernize-use-std-print",
"modernize-use-trailing-return-type",
"modernize-use-transparent-functors",
"modernize-use-uncaught-exceptions",
@@ -2693,6 +2806,7 @@
"openmp-exception-escape",
"openmp-use-default-none",
"performance-*",
"performance-avoid-endl",
"performance-faster-string-find",
"performance-for-range-copy",
"performance-implicit-conversion-in-loop",
@@ -2706,7 +2820,10 @@
"performance-no-*",
"performance-no-automatic-move",
"performance-no-int-to-ptr",
"performance-noexcept-*",
"performance-noexcept-destructor",
"performance-noexcept-move-constructor",
"performance-noexcept-swap",
"performance-trivially-destructible",
"performance-type-promotion-in-math-fn",
"performance-unnecessary-*",
@@ -2717,7 +2834,9 @@
"portability-simd-intrinsics",
"portability-std-allocator-const",
"readability-*",
"readability-avoid-*",
"readability-avoid-const-params-in-decls",
"readability-avoid-unconditional-preprocessor-if",
"readability-braces-around-statements",
"readability-const-return-type",
"readability-container-*",
@@ -2743,6 +2862,7 @@
"readability-misplaced-array-index",
"readability-named-parameter",
"readability-non-const-parameter",
"readability-operators-representation",
"readability-qualified-auto",
"readability-redundant-*",
"readability-redundant-access-specifiers",
@@ -3016,13 +3136,13 @@
"category": "C/C++"
},
{
"command": "C_Cpp.SelectDefaultCompiler",
"title": "%c_cpp.command.selectDefaultCompiler.title%",
"command": "C_Cpp.SelectIntelliSenseConfiguration",
"title": "%c_cpp.command.selectIntelliSenseConfiguration.title%",
"category": "C/C++"
},
{
"command": "C_Cpp.SelectIntelliSenseConfiguration",
"title": "%c_cpp.command.selectIntelliSenseConfiguration.title%",
"command": "C_Cpp.InstallCompiler",
"title": "%c_cpp.command.installCompiler.title%",
"category": "C/C++"
},
{
@@ -3222,6 +3342,24 @@
"command": "C_Cpp.SwitchHeaderSource",
"key": "Alt+O",
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && editorTextFocus && !(config.C_Cpp.intelliSenseEngine =~ /^[dD]isabled$/)"
},
{
"command": "editor.action.codeAction",
"key": "ctrl+shift+r ctrl+i",
"args": {
"kind": "refactor.inline.macro",
"apply": "first"
},
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && editorTextFocus && !(config.C_Cpp.intelliSenseEngine =~ /^[dD]isabled$/)"
},
{
"command": "editor.action.codeAction",
"key": "ctrl+shift+r ctrl+e",
"args": {
"kind": "refactor.extract.function",
"apply": "first"
},
"when": "editorLangId =~ /^(c|(cuda-)?cpp)$/ && editorTextFocus && !(config.C_Cpp.intelliSenseEngine =~ /^[dD]isabled$/)"
}
],
"debuggers": [
@@ -5634,7 +5772,7 @@
"when": "cpptools.hasReferencesResults"
},
{
"command": "C_Cpp.SelectDefaultCompiler",
"command": "C_Cpp.InstallCompiler",
"when": "never"
},
{
@@ -6115,31 +6253,57 @@
]
}
}
],
"codeActions": [
{
"languages": [
"c",
"cpp",
"cuda-cpp"
],
"actions": {
"kind": "refactor.inline.macro",
"title": "%c_cpp.codeActions.refactor.inline.macro.title%",
"description": "%c_cpp.codeActions.refactor.inline.macro.description%"
}
},
{
"languages": [
"c",
"cpp",
"cuda-cpp"
],
"actions": {
"kind": "refactor.extract.function",
"title": "%c_cpp.codeActions.refactor.extract.function.title%",
"description": "%c_cpp.codeActions.refactor.extract.function.description%"
}
}
]
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"compile": "node ./tools/prepublish.js && gulp copy-walkthrough-media && gulp generate-native-strings && gulp translations-generate && webpack --mode production --env vscode_nls",
"compile-dev": "node ./tools/prepublish.js && gulp copy-walkthrough-media && gulp generate-native-strings && webpack --mode development",
"compile-watch": "node ./tools/prepublish.js && gulp copy-walkthrough-media && gulp generate-native-strings && gulp translations-generate && webpack --mode production --env vscode_nls --watch --progress",
"compile-dev-watch": "node ./tools/prepublish.js && gulp copy-walkthrough-media && gulp generate-native-strings && webpack --mode development --watch --progress",
"compile-unit-tests": "tsc --build test.tsconfig.json",
"compile-watch-unit-tests": "tsc --build test.tsconfig.json --watch",
"generateOptionsSchema": "node ./tools/prepublish.js && node ./out/tools/generateOptionsSchema.js",
"generate-native-strings": "node ./tools/prepublish.js && gulp generate-native-strings",
"translations-export": "node ./tools/prepublish.js && gulp generate-native-strings && gulp translations-export",
"translations-generate": "node ./tools/prepublish.js && set NODE_OPTIONS=--no-experimental-fetch && gulp translations-generate",
"translations-import": "node ./tools/prepublish.js && gulp translations-import",
"copy-walkthrough-media": "node ./tools/prepublish.js && gulp copy-walkthrough-media",
"prepublishjs": "node ./tools/prepublish.js",
"pretest": "tsc -p test.tsconfig.json",
"lint": "gulp lint",
"unitTests": "tsc -p test.tsconfig.json && node ./out/test/unitTests/runTest.js",
"internalUnitTests": "tsc -p test.tsconfig.json && mocha ./out/test/internalUnitTests/test*.js",
"integrationTests": "tsc -p test.tsconfig.json && node ./out/test/integrationTests/languageServer/runTest.js",
"intelliSenseFeaturesTests": "tsc -p test.tsconfig.json && node ./out/test/integrationTests/IntelliSenseFeatures/runTest.js",
"import-edge-strings": "node ./import_edge_strings.js",
"postinstall": "npx vscode-dts dev && npx vscode-dts main"
"scripts": "ts-node -T .scripts/scripts.ts",
"show": "ts-node -T .scripts/clean.ts show",
"clean": "ts-node -T .scripts/clean.ts",
"test": "yarn install && (yarn verify prep --quiet || yarn prep) && (yarn verify compiled --quiet || yarn build) && ts-node -T .scripts/test.ts",
"code": "yarn install && (yarn verify compiled --quiet || yarn build) && yarn verify binaries && ts-node -T .scripts/code.ts",
"verify": "ts-node -T .scripts/verify.ts",
"prep": "yarn prep:dts && yarn copy-walkthrough-media && yarn generate-native-strings && yarn translations-generate",
"lint": "yarn install && eslint -c .eslintrc.js --report-unused-disable-directives src test ui .scripts",
"compile": "yarn install && (yarn verify prep --quiet || yarn prep) && yarn build",
"watch": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build tsconfig.json --watch",
"rebuild": "yarn install && yarn clean && yarn prep && yarn build",
"vscode:prepublish": "yarn install && yarn clean && yarn webpack",
"webpack": "yarn install && (yarn verify prep --quiet || yarn prep) && tsc --build ui.tsconfig.json && webpack --mode production --env vscode_nls",
"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",
"translations-export": "yarn install && yarn prep && yarn generate-native-strings && gulp translations-export",
"translations-generate": "set NODE_OPTIONS=--no-experimental-fetch && gulp translations-generate",
"translations-import": "gulp translations-import",
"import-edge-strings": "ts-node -T ./.scripts/import_edge_strings.ts",
"prep:dts": "yarn verify dts --quiet || (npx vscode-dts dev && npx vscode-dts main)",
"build": "yarn prep:dts && echo [Building TypeScript code] && tsc --build tsconfig.json"
},
"devDependencies": {
"@octokit/rest": "^18.12.0",
@@ -6154,23 +6318,21 @@
"@types/tmp": "^0.1.0",
"@types/which": "^1.3.2",
"@types/yauzl": "^2.9.1",
"@typescript-eslint/eslint-plugin": "^5.59.11",
"@typescript-eslint/parser": "^5.59.11",
"@typescript-eslint/eslint-plugin": "^6.1.0",
"@typescript-eslint/parser": "^6.1.0",
"eslint-plugin-header": "^3.1.1",
"@vscode/test-electron": "^2.3.3",
"@vscode/dts": "^0.4.0",
"async-child-process": "^1.1.1",
"await-notify": "^1.0.1",
"eslint": "^8.42.0",
"eslint": "^8.45.0",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsdoc": "^46.2.6",
"eslint-plugin-jsdoc": "^46.4.4",
"event-stream": "^4.0.1",
"fs-extra": "^8.1.0",
"gulp": "^4.0.2",
"gulp-env": "^0.4.0",
"gulp-eslint-new": "^1.8.0",
"gulp-filter": "^6.0.0",
"gulp-mocha": "^8.0.0",
"gulp-sourcemaps": "^2.6.5",
"gulp-typescript": "^5.0.1",
"minimist": "^1.2.7",
@@ -6179,6 +6341,7 @@
"parse5": "^5.1.0",
"parse5-traverse": "^1.0.3",
"ts-loader": "^8.1.0",
"ts-node": "10.9.1",
"typescript": "^5.1.3",
"@vscode/debugadapter": "^1.61.0",
"@vscode/debugprotocol": "^1.61.0",
@@ -6197,6 +6360,7 @@
"minimatch": "^3.0.5",
"mkdirp": "^0.5.5",
"node-loader": "^2.0.0",
"node-stream-zip": "^1.15.0",
"plist": "^3.0.5",
"posix-getopt": "^1.2.1",
"shell-quote": "^1.7.3",
@@ -6206,8 +6370,7 @@
"vscode-languageclient": "^8.1.0-next.4",
"vscode-nls": "^5.0.0",
"vscode-tas-client": "^0.1.27",
"which": "^2.0.2",
"yauzl": "^2.10.0"
"which": "^2.0.2"
},
"resolutions": {
"chokidar": "^3.5.3",
+699 -125
View File
@@ -1,18 +1,18 @@
{
"c_cpp.subheaders.intelliSense.title" : "IntelliSense",
"c_cpp.subheaders.formatting.title" : "Formatting",
"c_cpp.subheaders.codeDocumentation.title" : "Code Documentation",
"c_cpp.subheaders.codeAnalysis.title" : "Code Analysis",
"c_cpp.subheaders.debugging.title" : "Debugging",
"c_cpp.subheaders.resourceManagement.title" : "Resource Management",
"c_cpp.subheaders.miscellaneous.title" : "Miscellaneous",
"c_cpp.subheaders.intelliSense.title": "IntelliSense",
"c_cpp.subheaders.formatting.title": "Formatting",
"c_cpp.subheaders.codeDocumentation.title": "Code Documentation",
"c_cpp.subheaders.codeAnalysis.title": "Code Analysis",
"c_cpp.subheaders.debugging.title": "Debugging",
"c_cpp.subheaders.resourceManagement.title": "Resource Management",
"c_cpp.subheaders.miscellaneous.title": "Miscellaneous",
"c_cpp.capabilities.untrustedWorkspaces.description": "Multiple settings can cause processes local to the workspace to be executed, e.g. C_Cpp.clang_format_path, C_Cpp.codeAnalysis.clangTidy.path, C_Cpp.addNodeAddonIncludePaths, C_Cpp.default.compilerPath, C_Cpp.default.configurationProvider, and C_Cpp.default.compileCommands, and the equivalent properties in c_cpp_properties.json.",
"c_cpp.command.configurationSelect.title": "Select a Configuration...",
"c_cpp.command.configurationProviderSelect.title": "Change Configuration Provider...",
"c_cpp.command.configurationEditJSON.title": "Edit Configurations (JSON)",
"c_cpp.command.configurationEditUI.title": "Edit Configurations (UI)",
"c_cpp.command.selectDefaultCompiler.title": "Select Default Compiler...",
"c_cpp.command.selectIntelliSenseConfiguration.title": "Select IntelliSense Configuration...",
"c_cpp.command.installCompiler.title": "Install a C++ Compiler",
"c_cpp.command.rescanCompilers.title": "Rescan for Compilers",
"c_cpp.command.switchHeaderSource.title": "Switch Header/Source",
"c_cpp.command.enableErrorSquiggles.title": "Enable Error Squiggles",
@@ -48,66 +48,301 @@
"c_cpp.command.activeSshTarget.title": "Get the active SSH target",
"c_cpp.command.refreshCppSshTargetsView.title": "Refresh",
"c_cpp.command.sshTerminal.title": "Connect to this SSH target in a new terminal",
"c_cpp.configuration.maxConcurrentThreads.markdownDescription": { "message": "The maximum number of concurrent threads to use for language service processing. The value is a hint and may not always be used. The default of `null` (empty) uses the number of logical processors available.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.maxCachedProcesses.markdownDescription": { "message": "The maximum number of cached processes to use for language service processing. The default of `null` (empty) uses twice the number of logical processors available.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.maxMemory.markdownDescription": { "message": "The maximum memory (in MB) available for language service processing. Fewer processes will be cached and run concurrently after this memory usage is exceeded. The default of `null` (empty) uses the system's free memory.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSense.maxCachedProcesses.markdownDescription": { "message": "The maximum number of IntelliSense processes to keep running. The default of `null` (empty) uses value inherited from `#C_Cpp.maxCachedProcesses#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSense.maxMemory.markdownDescription": { "message": "Older IntelliSense processes will shut down before new processes are created after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.references.maxConcurrentThreads.markdownDescription": { "message": "The maximum number of concurrent threads to use for 'Find All References' and 'Rename'. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxConcurrentThreads#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.references.maxCachedProcesses.markdownDescription": { "message": "The maximum number of processes to keep in memory for 'Find All References' and 'Rename'. The default of `0` disables this feature. The value of `null` (empty) uses the value inherited from `#C_Cpp.maxCachedProcesses#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.references.maxMemory.markdownDescription": { "message": "Fewer 'Find All References' and 'Rename' processes will be cached and run concurrently after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.maxConcurrentThreads.markdownDescription": { "message": "The maximum number of concurrent threads to use for code analysis. The default of `null` (empty) uses half the value inherited from `#C_Cpp.maxConcurrentThreads#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.maxMemory.markdownDescription": { "message": "Fewer code analysis processes will run concurrently after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.updateDelay.markdownDescription": { "message": "Controls the delay in milliseconds before code analysis starts processing after a save is triggered from an edit when `#files.autoSave#` is `afterDelay` and `#C_Cpp.codeAnalysis.runAutomatically#` is `true`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.exclude.markdownDescription": { "message": "Configure glob patterns for excluding folders and files for code analysis. Files not under the workspace folder are always excluded. Inherits values from `#files.exclude#` and `#C_Cpp.files.exclude#`. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.excludeBoolean.markdownDescription": { "message": "The glob pattern to match file paths against. Set to `true` or `false` to enable or disable the pattern.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.excludeWhen.markdownDescription": { "message": "Additional check on the siblings of a matching file. Use `$(basename)` as variable for the matching file name.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.runAutomatically.markdownDescription": { "message": "If `true`, code analysis will run automatically on a file after it is opened or saved.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription": { "message": "If `true`, the 'Disable' code action will be shown when available (the next time code analysis is run). When the 'Disable' code action is used, it adds the warning code to the `C_Cpp.codeAnalysis.clangTidy.checks.disabled` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription": { "message": "If `true`, the 'Show Documentation for' code action will be shown when available (the next time code analysis is run).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.maxConcurrentThreads.markdownDescription": {
"message": "The maximum number of concurrent threads to use for language service processing. The value is a hint and may not always be used. The default of `null` (empty) uses the number of logical processors available.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.maxCachedProcesses.markdownDescription": {
"message": "The maximum number of cached processes to use for language service processing. The default of `null` (empty) uses twice the number of logical processors available.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.maxMemory.markdownDescription": {
"message": "The maximum memory (in MB) available for language service processing. Fewer processes will be cached and run concurrently after this memory usage is exceeded. The default of `null` (empty) uses the system's free memory.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSense.maxCachedProcesses.markdownDescription": {
"message": "The maximum number of IntelliSense processes to keep running. The default of `null` (empty) uses value inherited from `#C_Cpp.maxCachedProcesses#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSense.maxMemory.markdownDescription": {
"message": "Older IntelliSense processes will shut down before new processes are created after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.references.maxConcurrentThreads.markdownDescription": {
"message": "The maximum number of concurrent threads to use for 'Find All References' and 'Rename'. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxConcurrentThreads#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.references.maxCachedProcesses.markdownDescription": {
"message": "The maximum number of processes to keep in memory for 'Find All References' and 'Rename'. The default of `0` disables this feature. The value of `null` (empty) uses the value inherited from `#C_Cpp.maxCachedProcesses#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.references.maxMemory.markdownDescription": {
"message": "Fewer 'Find All References' and 'Rename' processes will be cached and run concurrently after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.maxConcurrentThreads.markdownDescription": {
"message": "The maximum number of concurrent threads to use for code analysis. The default of `null` (empty) uses half the value inherited from `#C_Cpp.maxConcurrentThreads#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.maxMemory.markdownDescription": {
"message": "Fewer code analysis processes will run concurrently after this memory usage (in MB) is exceeded. The default of `null` (empty) uses the value inherited from `#C_Cpp.maxMemory#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.updateDelay.markdownDescription": {
"message": "Controls the delay in milliseconds before code analysis starts processing after a save is triggered from an edit when `#files.autoSave#` is `afterDelay` and `#C_Cpp.codeAnalysis.runAutomatically#` is `true`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.exclude.markdownDescription": {
"message": "Configure glob patterns for excluding folders and files for code analysis. Files not under the workspace folder are always excluded. Inherits values from `#files.exclude#` and `#C_Cpp.files.exclude#`. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options).",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.excludeBoolean.markdownDescription": {
"message": "The glob pattern to match file paths against. Set to `true` or `false` to enable or disable the pattern.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.excludeWhen.markdownDescription": {
"message": "Additional check on the siblings of a matching file. Use `$(basename)` as variable for the matching file name.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.runAutomatically.markdownDescription": {
"message": "If `true`, code analysis will run automatically on a file after it is opened or saved.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDisable.markdownDescription": {
"message": "If `true`, the 'Disable' code action will be shown when available (the next time code analysis is run). When the 'Disable' code action is used, it adds the warning code to the `C_Cpp.codeAnalysis.clangTidy.checks.disabled` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showDocumentation.markdownDescription": {
"message": "If `true`, the 'Show Documentation for' code action will be shown when available (the next time code analysis is run).",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.description": "Controls which 'Clear' code analysis problem code action options are available. Changing the setting to show more options may require re-running code analysis.",
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.None.description": "Show no 'Clear' code actions.",
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllOnly.description": "Show only the 'Clear all' code action (or 'Clear all <type>' if there is only one type or 'Clear this' if there is only one problem).",
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllType.description": "Show the 'Clear all' code action (if there are multiple problem types) and the 'Clear all <type>' code action (or 'Clear this' if there is only one problem for the <type>)",
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.showClear.AllAndAllTypeAndThis.description": "Show the 'Clear all' (if there are multiple problem types), 'Clear all <type>' (if there are multiple problems for the <type>), and 'Clear this' code actions",
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.formatFixes.markdownDescription": { "message": "If `true`, formatting will be run on the lines changed by 'Fix' code actions.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.enabled.markdownDescription": { "message": "If `true`, code analysis using `clang-tidy` will be enabled and will run after a file is opened or saved if `#C_Cpp.codeAnalysis.runAutomatically#` is `true` (the default).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.path.markdownDescription": { "message": "The full path of the `clang-tidy` executable. If not specified, and `clang-tidy` is available in the environment path, that is used. If not found in the environment path, the `clang-tidy` bundled with the extension will be used.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.config.markdownDescription": { "message": "Specifies a `clang-tidy` configuration in YAML/JSON format: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`. When the value is empty, `clang-tidy` will attempt to find a file named `.clang-tidy` for each source file in its parent directories.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.fallbackConfig.markdownDescription": { "message": "Specifies a `clang-tidy` configuration in YAML/JSON format to be used as a fallback when `#C_Cpp.codeAnalysis.clangTidy.config#` is not set and no `.clang-tidy` file is found: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.headerFilter.markdownDescription": { "message": "A POSIX extended regular expression (ERE) matching the names of the headers to output diagnostics from. Diagnostics from the main file of each translation unit are always displayed. The `${workspaceFolder}` variable is supported (and is used as the default fallback value if no `.clang-tidy` file exists). If this option is not `null` (empty), it overrides the `HeaderFilterRegex` option in a `.clang-tidy` file, if any.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.args.markdownDescription": { "message": "Additional command line arguments to pass to `clang-tidy`. These take precedence over the equivalent `C_Cpp.codeAnalysis.clangTidy.*` settings.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.useBuildPath.markdownDescription": { "message": "If `true` and `compileCommands` is set, the `-p=<build-path>` argument is passed to `clang-tidy` instead of build arguments being passed after `--`. This may not work if environment variables aren't set so that system includes can be found.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.checks.enabled.markdownDescription": { "message": "List of enabled `clang-tidy` checks. The values are appended to the `Checks` in a `.clang-tidy` file or `#C_Cpp.codeAnalysis.clangTidy.config#`, if any. The default check `clang-analyzer-*` is always used unless it is explicitly disabled.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.checks.disabled.markdownDescription": { "message": "List of disabled `clang-tidy` checks. The values are appended to the `Checks` in a `.clang-tidy` file or `#C_Cpp.codeAnalysis.clangTidy.config#`, if any.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.codeAnalysis.clangTidy.codeAction.formatFixes.markdownDescription": {
"message": "If `true`, formatting will be run on the lines changed by 'Fix' code actions.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.enabled.markdownDescription": {
"message": "If `true`, code analysis using `clang-tidy` will be enabled and will run after a file is opened or saved if `#C_Cpp.codeAnalysis.runAutomatically#` is `true` (the default).",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.path.markdownDescription": {
"message": "The full path of the `clang-tidy` executable. If not specified, and `clang-tidy` is available in the environment path, that is used. If not found in the environment path, the `clang-tidy` bundled with the extension will be used.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.config.markdownDescription": {
"message": "Specifies a `clang-tidy` configuration in YAML/JSON format: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`. When the value is empty, `clang-tidy` will attempt to find a file named `.clang-tidy` for each source file in its parent directories.",
"comment": [
"Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.fallbackConfig.markdownDescription": {
"message": "Specifies a `clang-tidy` configuration in YAML/JSON format to be used as a fallback when `#C_Cpp.codeAnalysis.clangTidy.config#` is not set and no `.clang-tidy` file is found: `{Checks: '-*,clang-analyzer-*', CheckOptions: [{key: x, value: y}]}`.",
"comment": [
"Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.headerFilter.markdownDescription": {
"message": "A POSIX extended regular expression (ERE) matching the names of the headers to output diagnostics from. Diagnostics from the main file of each translation unit are always displayed. The `${workspaceFolder}` variable is supported (and is used as the default fallback value if no `.clang-tidy` file exists). If this option is not `null` (empty), it overrides the `HeaderFilterRegex` option in a `.clang-tidy` file, if any.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.args.markdownDescription": {
"message": "Additional command line arguments to pass to `clang-tidy`. These take precedence over the equivalent `C_Cpp.codeAnalysis.clangTidy.*` settings.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.useBuildPath.markdownDescription": {
"message": "If `true` and `compileCommands` is set, the `-p=<build-path>` argument is passed to `clang-tidy` instead of build arguments being passed after `--`. This may not work if environment variables aren't set so that system includes can be found.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.checks.enabled.markdownDescription": {
"message": "List of enabled `clang-tidy` checks. The values are appended to the `Checks` in a `.clang-tidy` file or `#C_Cpp.codeAnalysis.clangTidy.config#`, if any. The default check `clang-analyzer-*` is always used unless it is explicitly disabled.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeAnalysis.clangTidy.checks.disabled.markdownDescription": {
"message": "List of disabled `clang-tidy` checks. The values are appended to the `Checks` in a `.clang-tidy` file or `#C_Cpp.codeAnalysis.clangTidy.config#`, if any.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.formatting.description": "Configures the formatting engine.",
"c_cpp.configuration.formatting.clangFormat.markdownDescription": { "message": "`clang-format` will be used to format code.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.formatting.vcFormat.markdownDescription": { "message": "The Visual C++ formatting engine will be used to format code.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.formatting.Default.markdownDescription": { "message": "By default, `clang-format` will be used to format the code. However, the Visual C++ formatting engine will be used if an `.editorconfig` file with relevant settings is found nearer to the code being formatted and `#C_Cpp.clang_format_style#` is the default value: `file`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.formatting.Disabled.markdownDescription": { "message": "Code formatting will be disabled.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.braces.markdownDescription": { "message": "Braces are indented by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.formatting.clangFormat.markdownDescription": {
"message": "`clang-format` will be used to format code.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.formatting.vcFormat.markdownDescription": {
"message": "The Visual C++ formatting engine will be used to format code.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.formatting.Default.markdownDescription": {
"message": "By default, `clang-format` will be used to format the code. However, the Visual C++ formatting engine will be used if an `.editorconfig` file with relevant settings is found nearer to the code being formatted and `#C_Cpp.clang_format_style#` is the default value: `file`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.formatting.Disabled.markdownDescription": {
"message": "Code formatting will be disabled.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.braces.markdownDescription": {
"message": "Braces are indented by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.multiLineRelativeTo.description": "Determines what new line indentation is relative to.",
"c_cpp.configuration.vcFormat.indent.multiLineRelativeTo.outermostParenthesis.description": "Indent new line relative to the outermost open parenthesis.",
"c_cpp.configuration.vcFormat.indent.multiLineRelativeTo.innermostParenthesis.description": "Indent new line relative to the innermost open parenthesis.",
"c_cpp.configuration.vcFormat.indent.multiLineRelativeTo.statementBegin.description": "Indent new line relative to the beginning of the current statement.",
"c_cpp.configuration.vcFormat.indent.withinParentheses.markdownDescription": { "message": "When a new line is typed, it is aligned under the opening parenthesis or based on `#C_Cpp.vcFormat.indent.multiLineRelativeTo#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.withinParentheses.alignToParenthesis.markdownDescription": { "message": "New line is aligned under the opening parenthesis.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.withinParentheses.indent.markdownDescription": { "message": "New line is indented based on `#C_Cpp.vcFormat.indent.multiLineRelativeTo#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.withinParentheses.markdownDescription": {
"message": "When a new line is typed, it is aligned under the opening parenthesis or based on `#C_Cpp.vcFormat.indent.multiLineRelativeTo#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.withinParentheses.alignToParenthesis.markdownDescription": {
"message": "New line is aligned under the opening parenthesis.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.withinParentheses.indent.markdownDescription": {
"message": "New line is indented based on `#C_Cpp.vcFormat.indent.multiLineRelativeTo#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.preserveWithinParentheses.description": "In existing code, preserve the existing indent alignment of new lines within parentheses.",
"c_cpp.configuration.vcFormat.indent.caseLabels.markdownDescription": { "message": "Labels are indented relative to switch statements by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.caseContents.markdownDescription": { "message": "Code inside a `case` block is indented relative to its label by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.caseContentsWhenBlock.markdownDescription": { "message": "Indent braces following a case statement by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.lambdaBracesWhenParameter.markdownDescription": { "message": "Indent braces of lambdas used as function parameters relative to the start of the statement by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.caseLabels.markdownDescription": {
"message": "Labels are indented relative to switch statements by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.caseContents.markdownDescription": {
"message": "Code inside a `case` block is indented relative to its label by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.caseContentsWhenBlock.markdownDescription": {
"message": "Indent braces following a case statement by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.lambdaBracesWhenParameter.markdownDescription": {
"message": "Indent braces of lambdas used as function parameters relative to the start of the statement by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.gotoLabels.description": "The position of goto labels.",
"c_cpp.configuration.vcFormat.indent.gotoLabels.oneLeft.markdownDescription": { "message": "Position goto labels to the left of the current code indentation, by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.gotoLabels.leftmostColumn.markdownDescription": { "message": "Position goto labels at the leftmost edge of the code.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.gotoLabels.none.markdownDescription": { "message": "Goto labels will not be formatted.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.gotoLabels.oneLeft.markdownDescription": {
"message": "Position goto labels to the left of the current code indentation, by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.gotoLabels.leftmostColumn.markdownDescription": {
"message": "Position goto labels at the leftmost edge of the code.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.gotoLabels.none.markdownDescription": {
"message": "Goto labels will not be formatted.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.preprocessor.description": "The position of preprocessor directives.",
"c_cpp.configuration.vcFormat.indent.preprocessor.oneLeft.markdownDescription": { "message": "Preprocessor directives are positioned to the left of the current code indentation, by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.preprocessor.leftmostColumn.markdownDescription": { "message": "Preprocessor directives are positioned at the leftmost edge of the code.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.preprocessor.none.markdownDescription": { "message": "Preprocessor directives will not be formatted.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.accessSpecifiers.markdownDescription": { "message": "Access specifiers are indented relative to class or struct definitions by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.namespaceContents.markdownDescription": { "message": "Code is indented relative to its enclosing namespace by the amount specified in the `#editor.tabSize#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.indent.preprocessor.oneLeft.markdownDescription": {
"message": "Preprocessor directives are positioned to the left of the current code indentation, by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.preprocessor.leftmostColumn.markdownDescription": {
"message": "Preprocessor directives are positioned at the leftmost edge of the code.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.preprocessor.none.markdownDescription": {
"message": "Preprocessor directives will not be formatted.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.accessSpecifiers.markdownDescription": {
"message": "Access specifiers are indented relative to class or struct definitions by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.namespaceContents.markdownDescription": {
"message": "Code is indented relative to its enclosing namespace by the amount specified in the `#editor.tabSize#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.indent.preserveComments.description": "Indentation of comments is not changed during formatting operations.",
"c_cpp.configuration.vcFormat.newLine.beforeOpenBrace.namespace.description": "The position of opening braces for namespaces.",
"c_cpp.configuration.vcFormat.newLine.beforeOpenBrace.type.description": "The position of opening braces for type definitions.",
@@ -120,9 +355,24 @@
"c_cpp.configuration.vcFormat.newLine.scopeBracesOnSeparateLines.description": "Place opening and closing braces for scopes on separate lines.",
"c_cpp.configuration.vcFormat.newLine.closeBraceSameLine.emptyType.description": "For empty types, move closing braces to the same line as opening braces.",
"c_cpp.configuration.vcFormat.newLine.closeBraceSameLine.emptyFunction.description": "For empty function bodies, move closing braces to the same line as opening braces.",
"c_cpp.configuration.vcFormat.newLine.beforeCatch.markdownDescription": { "message": "Place `catch` and similar keywords on a new line.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.newLine.beforeElse.markdownDescription": { "message": "Place `else` on a new line.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.newLine.beforeWhileInDoWhile.markdownDescription": { "message": "Place `while` in a `do`-`while` loop on a new line.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.newLine.beforeCatch.markdownDescription": {
"message": "Place `catch` and similar keywords on a new line.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.newLine.beforeElse.markdownDescription": {
"message": "Place `else` on a new line.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.newLine.beforeWhileInDoWhile.markdownDescription": {
"message": "Place `while` in a `do`-`while` loop on a new line.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.space.beforeFunctionOpenParenthesis.description": "Spacing between function names and opening parentheses of argument lists.",
"c_cpp.configuration.vcFormat.space.beforeFunctionOpenParenthesis.insert.description": "Add a space before the opening parenthesis of a function.",
"c_cpp.configuration.vcFormat.space.beforeFunctionOpenParenthesis.remove.description": "Spaces before opening parenthesis of a function are removed.",
@@ -167,100 +417,410 @@
"c_cpp.configuration.vcFormat.space.aroundOperators.remove.description": "Spaces before and after the operator are removed.",
"c_cpp.configuration.vcFormat.space.aroundOperators.ignore.description": "Spaces are left as entered.",
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.description": "Wrapping options for blocks.",
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.oneLiners.markdownDescription": { "message": "A complete code block that is entered on one line is kept on one line, regardless of the values of any of the `C_Cpp.vcFormat.newLine.*` settings.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.allOneLineScopes.markdownDescription": { "message": "Any code where the opening and closing brace is entered on one line is kept on one line, regardless of the values of any of the `C_Cpp.vcFormat.newLine.*` settings.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.never.markdownDescription": { "message": "Code blocks are always formatted based on the values of the `C_Cpp.vcFormat.newLine.*` settings.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.clang_format_path.markdownDescription": { "message": "The full path of the `clang-format` executable. If not specified, and `clang-format` is available in the environment path, that is used. If not found in the environment path, the `clang-format` bundled with the extension will be used.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.clang_format_style.markdownDescription": { "message": "Coding style, currently supports: `Visual Studio`, `LLVM`, `Google`, `Chromium`, `Mozilla`, `WebKit`, `Microsoft`, `GNU`. Use `file` to load the style from a `.clang-format` file in the current or parent directory, or use `file:<path>/.clang-format` to reference a specific path. Use `{key: value, ...}` to set specific parameters. For example, the `Visual Studio` style is similar to: `{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }`.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' and the word 'path' in 'file:<path>/.clang-format' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.clang_format_fallbackStyle.markdownDescription": { "message": "Name of the predefined style used as a fallback in case `clang-format` is invoked with style `file` but the `.clang-format` file is not found. Possible values are `Visual Studio`, `LLVM`, `Google`, `Chromium`, `Mozilla`, `WebKit`, `Microsoft`, `GNU`, `none`, or use `{key: value, ...}` to set specific parameters. For example, the `Visual Studio` style is similar to: `{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }`.", "comment": [ "Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.clang_format_sortIncludes.markdownDescription": { "message": "If set, overrides the include sorting behavior determined by the `SortIncludes` parameter.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.oneLiners.markdownDescription": {
"message": "A complete code block that is entered on one line is kept on one line, regardless of the values of any of the `C_Cpp.vcFormat.newLine.*` settings.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.allOneLineScopes.markdownDescription": {
"message": "Any code where the opening and closing brace is entered on one line is kept on one line, regardless of the values of any of the `C_Cpp.vcFormat.newLine.*` settings.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.vcFormat.wrap.preserveBlocks.never.markdownDescription": {
"message": "Code blocks are always formatted based on the values of the `C_Cpp.vcFormat.newLine.*` settings.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.clang_format_path.markdownDescription": {
"message": "The full path of the `clang-format` executable. If not specified, and `clang-format` is available in the environment path, that is used. If not found in the environment path, the `clang-format` bundled with the extension will be used.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.clang_format_style.markdownDescription": {
"message": "Coding style, currently supports: `Visual Studio`, `LLVM`, `Google`, `Chromium`, `Mozilla`, `WebKit`, `Microsoft`, `GNU`. Use `file` to load the style from a `.clang-format` file in the current or parent directory, or use `file:<path>/.clang-format` to reference a specific path. Use `{key: value, ...}` to set specific parameters. For example, the `Visual Studio` style is similar to: `{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }`.",
"comment": [
"Words 'key' and 'value' in '{key: value, ...}' and the word 'path' in 'file:<path>/.clang-format' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.clang_format_fallbackStyle.markdownDescription": {
"message": "Name of the predefined style used as a fallback in case `clang-format` is invoked with style `file` but the `.clang-format` file is not found. Possible values are `Visual Studio`, `LLVM`, `Google`, `Chromium`, `Mozilla`, `WebKit`, `Microsoft`, `GNU`, `none`, or use `{key: value, ...}` to set specific parameters. For example, the `Visual Studio` style is similar to: `{ BasedOnStyle: LLVM, UseTab: Never, IndentWidth: 4, TabWidth: 4, BreakBeforeBraces: Allman, AllowShortIfStatementsOnASingleLine: false, IndentCaseLabels: false, ColumnLimit: 0, AccessModifierOffset: -4, NamespaceIndentation: All, FixNamespaceComments: false }`.",
"comment": [
"Words 'key' and 'value' in '{key: value, ...}' should be translated, but all other markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.clang_format_sortIncludes.markdownDescription": {
"message": "If set, overrides the include sorting behavior determined by the `SortIncludes` parameter.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSenseEngine.description": "Controls the IntelliSense provider.",
"c_cpp.configuration.intelliSenseEngine.default.description": "Provides context-aware results via a separate IntelliSense process.",
"c_cpp.configuration.intelliSenseEngine.tagParser.description": "Provides \"fuzzy\" results that are not context-aware.",
"c_cpp.configuration.intelliSenseEngine.disabled.description": "Turns off C/C++ language service features.",
"c_cpp.configuration.intelliSenseEngineFallback.markdownDescription": { "message": "Controls whether the IntelliSense engine will automatically switch to the Tag Parser for translation units containing `#include` errors.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.autocomplete.markdownDescription": { "message": "Controls the auto-completion provider. If `disabled` and you want word-based completion, you will also need to set `\"[cpp]\": {\"editor.wordBasedSuggestions\": true}` (and similarly for `c` and `cuda-cpp` languages).", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSenseEngineFallback.markdownDescription": {
"message": "Controls whether the IntelliSense engine will automatically switch to the Tag Parser for translation units containing `#include` errors.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.autocomplete.markdownDescription": {
"message": "Controls the auto-completion provider. If `disabled` and you want word-based completion, you will also need to set `\"[cpp]\": {\"editor.wordBasedSuggestions\": true}` (and similarly for `c` and `cuda-cpp` languages).",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.autocomplete.default.description": "Uses the active IntelliSense engine.",
"c_cpp.configuration.autocomplete.disabled.description": "Uses the word-based completion provided by Visual Studio Code.",
"c_cpp.configuration.errorSquiggles.description": "Controls whether suspected compile errors detected by the IntelliSense engine will be reported back to the editor. It also controls whether code analysis warnings are reported if includes can't be found. This setting is ignored by the Tag Parser engine.",
"c_cpp.configuration.dimInactiveRegions.description": "Controls whether inactive preprocessor blocks are colored differently than active code. This setting has no effect if IntelliSense is disabled or if using the Default High Contrast theme.",
"c_cpp.configuration.inactiveRegionOpacity.markdownDescription": { "message": "Controls the opacity of inactive preprocessor blocks. Scales between `0.1` and `1.0`. This setting only applies when inactive region dimming is enabled.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.inactiveRegionOpacity.markdownDescription": {
"message": "Controls the opacity of inactive preprocessor blocks. Scales between `0.1` and `1.0`. This setting only applies when inactive region dimming is enabled.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.inactiveRegionForegroundColor.description": "Controls the font coloring of inactive preprocessor blocks. Input is in the form a hexadecimal color code or a valid Theme Color. If not set, this defaults to the syntax coloring scheme of the editor. This setting only applies when inactive region dimming is enabled.",
"c_cpp.configuration.inactiveRegionBackgroundColor.description": "Controls the background coloring of inactive preprocessor blocks. Input is in the form a hexadecimal color code or a valid Theme Color. If not set, this defaults to transparent. This setting only applies when inactive region dimming is enabled.",
"c_cpp.configuration.inlayHints.autoDeclarationTypes.enabled.markdownDescription": { "message": "Display inlay hints for deduced type when `auto` is used in a declaration:\n```cpp \n\n auto index /* : int */ = 0;\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.autoDeclarationTypes.showOnLeft.markdownDescription": { "message": "Display inlay hints for deduced type when `auto` is used in a declaration on the left of the identifier:\n```cpp \n\n auto /* int */ index = 0;\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.enabled.markdownDescription": { "message": "Display inlay hints for parameter names:\n```cpp \n\n int a = getArea(/* width: */ x, /* height: */ y);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.hideLeadingUnderscores.markdownDescription": { "message": "Hide leading `_` in parameter name hints.", "comment": [ "Markdown text between `` is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.parameterNames.suppressWhenArgumentContainsName.markdownDescription": { "message": "Suppress parameter name hints when the argument text or inline comment contains the parameter name:\n```cpp \n\n int a = getArea(width, /* height: */ y);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.referenceOperator.enabled.markdownDescription": { "message": "Display the inlay hint reference operator `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* &first: */ str1, /* &last: */ str2);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.inlayHints.referenceOperator.showSpace.markdownDescription": { "message": "Controls whether a space is shown after `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* & first: */ str1, /* & last: */ str2);\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"c_cpp.configuration.loggingLevel.markdownDescription": { "message": "The verbosity of logging in the Output Panel. The order of levels from least verbose to most verbose is: `None` < `Error` < `Warning` < `Information` < `Debug`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.autoAddFileAssociations.markdownDescription": { "message": "Controls whether files are automatically added to `#files.associations#` when they are the target of a navigation operation from a C/C++ file.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.workspaceParsingPriority.markdownDescription": { "message": "Controls whether parsing of the non-active workspace files uses sleeps to avoid using 100% CPU. The values `highest`/`high`/`medium`/`low` correspond to approximately 100/75/50/25% CPU usage.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.workspaceSymbols.description": { "message": "The symbols to include in the query results when 'Go to Symbol in Workspace' is invoked.", "comment": [ "Text in '' is a command and should be translated in the same way that VS Code itself translates it." ] },
"c_cpp.configuration.exclusionPolicy.markdownDescription": { "message": "Instructs the extension when to use the `#files.exclude#` (and `#C_Cpp.files.exclude#`) setting when determining which files should be added to the code navigation database while traversing through the paths in the `browse.path` array. If your `#files.exclude#` setting only contains folders, then `checkFolders` is the best choice and will increase the speed at which the extension can initialize the code navigation database.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.inlayHints.autoDeclarationTypes.enabled.markdownDescription": {
"message": "Display inlay hints for deduced type when `auto` is used in a declaration:\n```cpp \n\n auto index /* : int */ = 0;\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.autoDeclarationTypes.showOnLeft.markdownDescription": {
"message": "Display inlay hints for deduced type when `auto` is used in a declaration on the left of the identifier:\n```cpp \n\n auto /* int */ index = 0;\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.parameterNames.enabled.markdownDescription": {
"message": "Display inlay hints for parameter names:\n```cpp \n\n int a = getArea(/* width: */ x, /* height: */ y);\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.parameterNames.hideLeadingUnderscores.markdownDescription": {
"message": "Hide leading `_` in parameter name hints.",
"comment": [
"Markdown text between `` is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.parameterNames.suppressWhenArgumentContainsName.markdownDescription": {
"message": "Suppress parameter name hints when the argument text or inline comment contains the parameter name:\n```cpp \n\n int a = getArea(width, /* height: */ y);\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.referenceOperator.enabled.markdownDescription": {
"message": "Display the inlay hint reference operator `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* &first: */ str1, /* &last: */ str2);\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.inlayHints.referenceOperator.showSpace.markdownDescription": {
"message": "Controls whether a space is shown after `&` for parameters passed by non-const reference:\n```cpp \n\n swap(/* & first: */ str1, /* & last: */ str2);\n```",
"comment": [
"Markdown text between `` and the text inside ``` block is code and should not be localized."
]
},
"c_cpp.configuration.loggingLevel.markdownDescription": {
"message": "The verbosity of logging in the Output Panel. The order of levels from least verbose to most verbose is: `None` < `Error` < `Warning` < `Information` < `Debug`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.autoAddFileAssociations.markdownDescription": {
"message": "Controls whether files are automatically added to `#files.associations#` when they are the target of a navigation operation from a C/C++ file.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.workspaceParsingPriority.markdownDescription": {
"message": "Controls whether parsing of the non-active workspace files uses sleeps to avoid using 100% CPU. The values `highest`/`high`/`medium`/`low` correspond to approximately 100/75/50/25% CPU usage.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.workspaceSymbols.description": {
"message": "The symbols to include in the query results when 'Go to Symbol in Workspace' is invoked.",
"comment": [
"Text in '' is a command and should be translated in the same way that VS Code itself translates it."
]
},
"c_cpp.configuration.exclusionPolicy.markdownDescription": {
"message": "Instructs the extension when to use the `#files.exclude#` (and `#C_Cpp.files.exclude#`) setting when determining which files should be added to the code navigation database while traversing through the paths in the `browse.path` array. If your `#files.exclude#` setting only contains folders, then `checkFolders` is the best choice and will increase the speed at which the extension can initialize the code navigation database.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.exclusionPolicy.checkFolders.description": "The exclusion filters will only be evaluated once per folder (individual files are not checked).",
"c_cpp.configuration.exclusionPolicy.checkFilesAndFolders.description": "The exclusion filters will be evaluated against every file and folder encountered.",
"c_cpp.configuration.preferredPathSeparator.markdownDescription": { "message": "The character used as a path separator for `#include` auto-completion results.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.simplifyStructuredComments.markdownDescription": { "message": "If `true`, tooltips of hover and auto-complete will only display certain labels of structured comments. Otherwise, all comments are displayed.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.doxygen.generateOnType.description": "Controls whether to automatically insert the Doxygen comment after typing the chosen comment style.",
"c_cpp.configuration.preferredPathSeparator.markdownDescription": {
"message": "The character used as a path separator for `#include` auto-completion results.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.simplifyStructuredComments.markdownDescription": {
"message": "If `true`, tooltips of hover and auto-complete will only display certain labels of structured comments. Otherwise, all comments are displayed.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.doxygen.generateOnType.description": "Controls whether to automatically insert the Doxygen comment after typing the chosen comment style.",
"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": { "message": "The pattern that begins a multiline or single line comment block. The continuation pattern defaults to ` * ` for multiline comment blocks or this string for single line comment blocks.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.commentContinuationPatterns.items.anyof.string.markdownDescription": {
"message": "The pattern that begins a multiline or single line comment block. The continuation pattern defaults to ` * ` for multiline comment blocks or this string for single line comment blocks.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.commentContinuationPatterns.items.anyof.object.begin.description": "The pattern that begins a multiline or single line comment block.",
"c_cpp.configuration.commentContinuationPatterns.items.anyof.object.continue.description": "The text that will be inserted on the next line when Enter is pressed inside a multiline or single line comment block.",
"c_cpp.configuration.commentContinuationPatterns.description": "Defines the editor behavior for when the Enter key is pressed inside a multiline or single line comment block.",
"c_cpp.configuration.configurationWarnings.description": "Determines whether pop up notifications will be shown when a configuration provider extension is unable to provide a configuration for a source file.",
"c_cpp.configuration.intelliSenseCachePath.markdownDescription": { "message": "Defines the folder path for cached precompiled headers used by IntelliSense. The default cache path is `%LocalAppData%/Microsoft/vscode-cpptools` on Windows, `$XDG_CACHE_HOME/vscode-cpptools/` on Linux (or `$HOME/.cache/vscode-cpptools/` if `XDG_CACHE_HOME` is not defined), and `$HOME/Library/Caches/vscode-cpptools/` on macOS. The default path will be used if no path is specified or if a specified path is invalid.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSenseCacheSize.markdownDescription": { "message": "Maximum size of the per-workspace hard drive space in megabytes (MB) for cached precompiled headers; the actual usage may fluctuate around this value. The default size is `5120` MB. Precompiled header caching is disabled when the size is `0`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSenseMemoryLimit.markdownDescription": { "message": "Memory usage limit in megabytes (MB) of an IntelliSense process. The default is `4096` and the maximum is `16384`. The extension will shutdown and restart an IntelliSense process when it exceeds the limit.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.intelliSenseCachePath.markdownDescription": {
"message": "Defines the folder path for cached precompiled headers used by IntelliSense. The default cache path is `%LocalAppData%/Microsoft/vscode-cpptools` on Windows, `$XDG_CACHE_HOME/vscode-cpptools/` on Linux (or `$HOME/.cache/vscode-cpptools/` if `XDG_CACHE_HOME` is not defined), and `$HOME/Library/Caches/vscode-cpptools/` on macOS. The default path will be used if no path is specified or if a specified path is invalid.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSenseCacheSize.markdownDescription": {
"message": "Maximum size of the per-workspace hard drive space in megabytes (MB) for cached precompiled headers; the actual usage may fluctuate around this value. The default size is `5120` MB. Precompiled header caching is disabled when the size is `0`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSenseMemoryLimit.markdownDescription": {
"message": "Memory usage limit in megabytes (MB) of an IntelliSense process. The default is `4096` and the maximum is `16384`. The extension will shutdown and restart an IntelliSense process when it exceeds the limit.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.intelliSenseUpdateDelay.description": "Controls the delay in milliseconds before IntelliSense starts updating after a modification.",
"c_cpp.configuration.default.includePath.markdownDescription": { "message": "The value to use in a configuration if `includePath` is not specified in `c_cpp_properties.json`. If `includePath` is specified, add `${default}` to the array to insert the values from this setting. Usually, this should not include system includes; instead, set `#C_Cpp.default.compilerPath#`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.defines.markdownDescription": { "message": "The value to use in a configuration if `defines` is not specified, or the values to insert if `${default}` is present in `defines`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.macFrameworkPath.markdownDescription": { "message": "The value to use in a configuration if `macFrameworkPath` is not specified, or the values to insert if `${default}` is present in `macFrameworkPath`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.windowsSdkVersion.markdownDescription": { "message": "Version of the Windows SDK include path to use on Windows, e.g. `10.0.17134.0`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.compileCommands.markdownDescription": { "message": "The value to use in a configuration if `compileCommands` is either not specified, or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.forcedInclude.markdownDescription": { "message": "The value to use in a configuration if `forcedInclude` is not specified, or the values to insert if `${default}` is present in `forcedInclude`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.intelliSenseMode.markdownDescription": { "message": "The value to use in a configuration if `intelliSenseMode` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.compilerPath.markdownDescription": { "message": "The value to use in a configuration if `compilerPath` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.compilerArgs.markdownDescription": { "message": "The value to use in configuration if `compilerArgs` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.cStandard.markdownDescription": { "message": "The value to use in a configuration if `cStandard` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.cppStandard.markdownDescription": { "message": "The value to use in a configuration if `cppStandard` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.configurationProvider.markdownDescription": { "message": "The value to use in a configuration if `configurationProvider` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.mergeConfigurations.markdownDescription": { "message": "Set to `true` to merge include paths, defines, and forced includes with those from a configuration provider.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.browse.path.markdownDescription": { "message": "The value to use in a configuration if `browse.path` is not specified, or the values to insert if `${default}` is present in `browse.path`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.browse.databaseFilename.markdownDescription": { "message": "The value to use in a configuration if `browse.databaseFilename` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.browse.limitSymbolsToIncludedHeaders.markdownDescription": { "message": "The value to use in a configuration if `browse.limitSymbolsToIncludedHeaders` is either not specified or set to `${default}`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.systemIncludePath.markdownDescription": { "message": "The value to use for the system include path. If set, it overrides the system include path acquired via `compilerPath` and `compileCommands` settings.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.enableConfigurationSquiggles.markdownDescription": { "message": "Controls whether the extension will report errors detected in `c_cpp_properties.json`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.customConfigurationVariables.markdownDescription": { "message": "The value to use in a configuration if `customConfigurationVariables` is not set, or the values to insert if `${default}` is present as a key in `customConfigurationVariables`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.updateChannel.markdownDescription": { "message": "Set to `Insiders` to automatically download and install the latest Insiders builds of the extension, which include upcoming features and bug fixes.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.includePath.markdownDescription": {
"message": "The value to use in a configuration if `includePath` is not specified in `c_cpp_properties.json`. If `includePath` is specified, add `${default}` to the array to insert the values from this setting. Usually, this should not include system includes; instead, set `#C_Cpp.default.compilerPath#`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.defines.markdownDescription": {
"message": "The value to use in a configuration if `defines` is not specified, or the values to insert if `${default}` is present in `defines`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.macFrameworkPath.markdownDescription": {
"message": "The value to use in a configuration if `macFrameworkPath` is not specified, or the values to insert if `${default}` is present in `macFrameworkPath`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.windowsSdkVersion.markdownDescription": {
"message": "Version of the Windows SDK include path to use on Windows, e.g. `10.0.17134.0`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.compileCommands.markdownDescription": {
"message": "The value to use in a configuration if `compileCommands` is either not specified, or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.forcedInclude.markdownDescription": {
"message": "The value to use in a configuration if `forcedInclude` is not specified, or the values to insert if `${default}` is present in `forcedInclude`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.intelliSenseMode.markdownDescription": {
"message": "The value to use in a configuration if `intelliSenseMode` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.compilerPath.markdownDescription": {
"message": "The value to use in a configuration if `compilerPath` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.compilerArgs.markdownDescription": {
"message": "The value to use in configuration if `compilerArgs` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.cStandard.markdownDescription": {
"message": "The value to use in a configuration if `cStandard` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.cppStandard.markdownDescription": {
"message": "The value to use in a configuration if `cppStandard` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.configurationProvider.markdownDescription": {
"message": "The value to use in a configuration if `configurationProvider` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.mergeConfigurations.markdownDescription": {
"message": "Set to `true` to merge include paths, defines, and forced includes with those from a configuration provider.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.browse.path.markdownDescription": {
"message": "The value to use in a configuration if `browse.path` is not specified, or the values to insert if `${default}` is present in `browse.path`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.browse.databaseFilename.markdownDescription": {
"message": "The value to use in a configuration if `browse.databaseFilename` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.browse.limitSymbolsToIncludedHeaders.markdownDescription": {
"message": "The value to use in a configuration if `browse.limitSymbolsToIncludedHeaders` is either not specified or set to `${default}`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.systemIncludePath.markdownDescription": {
"message": "The value to use for the system include path. If set, it overrides the system include path acquired via `compilerPath` and `compileCommands` settings.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.enableConfigurationSquiggles.markdownDescription": {
"message": "Controls whether the extension will report errors detected in `c_cpp_properties.json`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.default.customConfigurationVariables.markdownDescription": {
"message": "The value to use in a configuration if `customConfigurationVariables` is not set, or the values to insert if `${default}` is present as a key in `customConfigurationVariables`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.updateChannel.markdownDescription": {
"message": "Set to `Insiders` to automatically download and install the latest Insiders builds of the extension, which include upcoming features and bug fixes.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.updateChannel.deprecationMessage": "This setting is deprecated. Pre-release extensions are now available via the Marketplace.",
"c_cpp.configuration.default.dotConfig.markdownDescription": { "message": "The value to use in a configuration if `dotConfig` is not specified, or the value to insert if `${default}` is present in `dotConfig`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.default.dotConfig.markdownDescription": {
"message": "The value to use in a configuration if `dotConfig` is not specified, or the value to insert if `${default}` is present in `dotConfig`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.experimentalFeatures.description": "Controls whether \"experimental\" features are usable.",
"c_cpp.configuration.suggestSnippets.markdownDescription": { "message": "If `true`, snippets are provided by the language server.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.caseSensitiveFileSupport.markdownDescription": { "message": "If set to `default`, the file system of the workspace is assumed to be case insensitive on Windows and case sensitive on macOS or Linux. If set to `enabled`, the file system of the workspace is assumed to be case sensitive on Windows.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.enhancedColorization.markdownDescription": { "message": "If enabled, code is colorized based on IntelliSense. This setting only applies if `#C_Cpp.intelliSenseEngine#` is set to `default`.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.suggestSnippets.markdownDescription": {
"message": "If `true`, snippets are provided by the language server.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.caseSensitiveFileSupport.markdownDescription": {
"message": "If set to `default`, the file system of the workspace is assumed to be case insensitive on Windows and case sensitive on macOS or Linux. If set to `enabled`, the file system of the workspace is assumed to be case sensitive on Windows.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.enhancedColorization.markdownDescription": {
"message": "If enabled, code is colorized based on IntelliSense. This setting only applies if `#C_Cpp.intelliSenseEngine#` is set to `default`.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.codeFolding.description": "If enabled, code folding ranges are provided by the language server.",
"c_cpp.configuration.markdownInComments.description": "Select whether markdown will be available in the hover tooltip. By default, only a subset of markdown will be applied to comments in the hover tooltip.",
"c_cpp.configuration.markdownInComments.subsetEnabled.description": "Enable all markdown features in the hover tooltip except those that include the '_' and '*' characters.",
"c_cpp.configuration.markdownInComments.enabled.description": "Enable all markdown features in the hover tooltip.",
"c_cpp.configuration.markdownInComments.disabled.description": "Disable all markdown features in the hover tooltip.",
"c_cpp.configuration.hover.description": "If disabled, hover details are no longer provided by the language server.",
"c_cpp.configuration.vcpkg.enabled.markdownDescription": { "message": "Enable integration services for the [vcpkg dependency manager](https://aka.ms/vcpkg/).", "comment": [ "Markdown text between () should not be altered: https://en.wikipedia.org/wiki/Markdown" ] },
"c_cpp.configuration.addNodeAddonIncludePaths.markdownDescription": { "message": "Add include paths from `nan` and `node-addon-api` when they are dependencies.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.renameRequiresIdentifier.markdownDescription": { "message": "If `true`, 'Rename Symbol' will require a valid C/C++ identifier.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.autocompleteAddParentheses.markdownDescription": { "message": "If `true`, autocomplete will automatically add `(` after function calls, in which case `)` may also be added, depending on the value of the `#editor.autoClosingBrackets#` setting.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.filesExclude.markdownDescription": { "message": "Configure glob patterns for excluding folders (and files if `#C_Cpp.exclusionPolicy#` is changed). These are specific to the C/C++ extension and are in addition to `#files.exclude#`, but unlike `#files.exclude#` they also apply to paths outside the current workspace folder and are not removed from the Explorer view. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options).", "comment": [ "Markdown text between `` and [) should not be translated and the capitalization, spacing, and punctuation (including the ``) should not be altered: https://en.wikipedia.org/wiki/Markdown" ] },
"c_cpp.configuration.filesExcludeBoolean.markdownDescription": { "message": "The glob pattern to match file paths against. Set to `true` or `false` to enable or disable the pattern.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.filesExcludeWhen.markdownDescription": { "message": "Additional check on the siblings of a matching file. Use `$(basename)` as variable for the matching file name.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.debugger.useBacktickCommandSubstitution.markdownDescription": { "message": "If `true`, debugger shell command substitution will use obsolete backtick ``(`)``.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.configuration.vcpkg.enabled.markdownDescription": {
"message": "Enable integration services for the [vcpkg dependency manager](https://aka.ms/vcpkg/).",
"comment": [
"Markdown text between () should not be altered: https://en.wikipedia.org/wiki/Markdown"
]
},
"c_cpp.configuration.addNodeAddonIncludePaths.markdownDescription": {
"message": "Add include paths from `nan` and `node-addon-api` when they are dependencies.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.renameRequiresIdentifier.markdownDescription": {
"message": "If `true`, 'Rename Symbol' will require a valid C/C++ identifier.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.autocompleteAddParentheses.markdownDescription": {
"message": "If `true`, autocomplete will automatically add `(` after function calls, in which case `)` may also be added, depending on the value of the `#editor.autoClosingBrackets#` setting.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.filesExclude.markdownDescription": {
"message": "Configure glob patterns for excluding folders (and files if `#C_Cpp.exclusionPolicy#` is changed). These are specific to the C/C++ extension and are in addition to `#files.exclude#`, but unlike `#files.exclude#` they also apply to paths outside the current workspace folder and are not removed from the Explorer view. Read more about glob patterns [here](https://code.visualstudio.com/docs/editor/codebasics#_advanced-search-options).",
"comment": [
"Markdown text between `` and [) should not be translated and the capitalization, spacing, and punctuation (including the ``) should not be altered: https://en.wikipedia.org/wiki/Markdown"
]
},
"c_cpp.configuration.filesExcludeBoolean.markdownDescription": {
"message": "The glob pattern to match file paths against. Set to `true` or `false` to enable or disable the pattern.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.filesExcludeWhen.markdownDescription": {
"message": "Additional check on the siblings of a matching file. Use `$(basename)` as variable for the matching file name.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.debugger.useBacktickCommandSubstitution.markdownDescription": {
"message": "If `true`, debugger shell command substitution will use obsolete backtick ``(`)``.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.configuration.legacyCompilerArgsBehavior.markdownDescription": "Enable pre-v1.10.0 behavior for how shell escaping is handled in compiler arg settings. Shell escaping is no longer expected or supported by default in arg arrays starting in v1.10.0.",
"c_cpp.configuration.legacyCompilerArgsBehavior.deprecationMessage": "This setting is temporary to support transitioning to corrected behavior in v1.10.0.",
"c_cpp.configuration.sshTargetsView.description": "Controls whether the SSH Targets view is visible. By default, enable the view when an SSH command is invoked.",
"c_cpp.contributes.views.cppReferencesView.title": "C/C++: Other references results",
"c_cpp.contributes.views.sshTargetsView.title": { "message": "Cpptools: SSH targets", "comment": [ "Do not localize `Cpptools`." ] },
"c_cpp.contributes.viewsWelcome.contents": { "message": "To learn more about launch.json, see [Configuring C/C++ debugging](https://code.visualstudio.com/docs/cpp/launch-json-reference).", "comment": [ "Markdown text between () should not be altered: https://en.wikipedia.org/wiki/Markdown" ] },
"c_cpp.contributes.views.sshTargetsView.title": {
"message": "Cpptools: SSH targets",
"comment": [
"Do not localize `Cpptools`."
]
},
"c_cpp.contributes.viewsWelcome.contents": {
"message": "To learn more about launch.json, see [Configuring C/C++ debugging](https://code.visualstudio.com/docs/cpp/launch-json-reference).",
"comment": [
"Markdown text between () should not be altered: https://en.wikipedia.org/wiki/Markdown"
]
},
"c_cpp.configuration.debugShortcut.description": "Show the \"Run and Debug\" play button and \"Add Debug Configuration\" gear in the editor title bar for C++ files.",
"c_cpp.debuggers.pipeTransport.description": "When present, this tells the debugger to connect to a remote computer using another executable as a pipe that will relay standard input/output between VS Code and the MI-enabled debugger backend executable (such as gdb).",
"c_cpp.debuggers.pipeTransport.default.pipeProgram": "enter the fully qualified path for the pipe program name, for example '/usr/bin/ssh'.",
@@ -396,7 +956,12 @@
"c_cpp.semanticTokenTypes.templateType.description": "Style for C++ template types.",
"c_cpp.semanticTokenTypes.operatorOverload.description": "Style for C++ overloaded operators.",
"c_cpp.semanticTokenTypes.memberOperatorOverload.description": "Style for C++ overloaded operator member functions.",
"c_cpp.semanticTokenTypes.newOperator.description": { "message": "Style for C++ `new` or `delete` operators.", "comment": [ "Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered." ] },
"c_cpp.semanticTokenTypes.newOperator.description": {
"message": "Style for C++ `new` or `delete` operators.",
"comment": [
"Markdown text between `` should not be translated or localized (they represent literal text) and the capitalization, spacing, and punctuation (including the ``) should not be altered."
]
},
"c_cpp.semanticTokenTypes.customLiteral.description": "Style for C++ user-defined literals.",
"c_cpp.semanticTokenTypes.numberLiteral.description": "Style for C++ user-defined literal numbers.",
"c_cpp.semanticTokenTypes.stringLiteral.description": "Style for C++ user-defined literal strings.",
@@ -411,8 +976,9 @@
"c_cpp.walkthrough.description": "Dive into VS Code's rich C++ development experience.",
"c_cpp.walkthrough.set.up.title": "Set up your C++ Environment",
"c_cpp.walkthrough.activating.description": "Activating the C++ extension to determine whether your C++ Environment has been set up.\nActivating Extension...",
"c_cpp.walkthrough.no.compilers.description": "We could not find a C++ compiler on your machine, which is required to use the C++ extension. Follow the instructions on the right to install one, then click “Find my new Compiler” below.\n[Find my new Compiler](command:C_Cpp.RescanCompilers?%7B%22sender%22%3A%22walkthrough%22%7D)",
"c_cpp.walkthrough.compilers.found.description": "The C++ extension works with a C++ compiler. Select one from those already on your machine by clicking the button below.\n[Select my Default Compiler](command:C_Cpp.SelectDefaultCompiler?%7B%22sender%22%3A%22walkthrough%22%7D)",
"c_cpp.walkthrough.no.compilers.windows.description": "We could not find a C++ compiler on your machine, which is required to use the C++ extension. Follow the instructions on the right to install one, then click “Find my new Compiler” below.\n[Find my new Compiler](command:C_Cpp.RescanCompilers?%22walkthrough%22)",
"c_cpp.walkthrough.no.compilers.description": "We could not find a C++ compiler on your machine, which is required to use the C++ extension. Either select “Install a C++ Compiler” to have a compiler installed for you or follow the instructions on the right to install one, then click “Find my new Compiler” below.\n[Install a C++ Compiler](command:C_Cpp.InstallCompiler?%22walkthrough%22)\n[Find my new Compiler](command:C_Cpp.RescanCompilers?%22walkthrough%22)",
"c_cpp.walkthrough.compilers.found.description": "The C++ extension works with a C++ compiler. Select one from those already on your machine by clicking the button below.\n[Select my Default Compiler](command:C_Cpp.SelectIntelliSenseConfiguration?%22walkthrough%22)",
"c_cpp.walkthrough.compilers.found.altText": "Image showing the select a default compiler quickpick and the list of compilers found on the users machine, one of which is selected.",
"c_cpp.walkthrough.create.cpp.file.title": "Create a C++ file",
"c_cpp.walkthrough.create.cpp.file.description": "[Open](command:toSide:workbench.action.files.openFile) or [create](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22cpp%22%7D) a C++ file. Be sure to save it with the \".cpp\" extension, such as \"helloworld.cpp\". \n[Create a C++ File](command:toSide:workbench.action.files.newUntitledFile?%7B%22languageId%22%3A%22cpp%22%7D)",
@@ -428,5 +994,13 @@
"c_cpp.walkthrough.customize.debugging.mac.description": "You can customize your debug configuration (e.g. to pass arguments to your program at run time) by selecting \"Add Debug Configuration\" to the right of the play button. The custom debug configuration is saved in your project's launch.json file. \n[Learn More](https://code.visualstudio.com/docs/cpp/config-linux#_debug-helloworldcpp)",
"c_cpp.walkthrough.customize.debugging.linux.description": "You can customize your debug configuration (e.g. to pass arguments to your program at run time) by selecting \"Add Debug Configuration\" to the right of the play button. The custom debug configuration is saved in your project's launch.json file. \n[Learn More](https://code.visualstudio.com/docs/cpp/config-msvc#_debug-helloworldcpp)",
"c_cpp.walkthrough.customize.debugging.windows.description": "You can customize your debug configuration (e.g. to pass arguments to your program at run time) by selecting \"Add Debug Configuration\" to the right of the play button. The custom debug configuration is saved in your project's launch.json file. \n[Learn More](https://code.visualstudio.com/docs/cpp/config-clang-mac#_debug-helloworldcpp)",
"c_cpp.walkthrough.customize.debugging.altText": "Image that shows Add Debug Configuration in the drop-down"
"c_cpp.walkthrough.customize.debugging.altText": "Image that shows Add Debug Configuration in the drop-down",
"c_cpp.codeActions.refactor.inline.macro.title": "Inline macro",
"c_cpp.codeActions.refactor.inline.macro.description": "Replace the macro invocation with the expanded code.",
"c_cpp.codeActions.refactor.extract.function.title": "Extract to function",
"c_cpp.codeActions.refactor.extract.function.description": "Extract the selected code to a free or member function.",
"c_cpp.configuration.refactoring.includeHeader.markdownDescription": "Controls whether to include the header file of a refactored function/symbol to its corresponding source file when doing a refactoring action, such as create declaration/definition.",
"c_cpp.configuration.refactoring.includeHeader.always.description": "Always include the header file if it is not included explicitly in its source file.",
"c_cpp.configuration.refactoring.includeHeader.ifNeeded.description": "Only include the header file if it is not included explicitly in its source file or through implicit inclusion.",
"c_cpp.configuration.refactoring.includeHeader.never.description": "Never include the header file."
}
+339
View File
@@ -0,0 +1,339 @@
# Developer Documentation
## Table of Contents
- [Table of Contents](#table-of-contents)
- [Setup](#setup)
- [Required Tools](#required-tools)
- [Setting up the repository](#setting-up-the-repository)
- [Building the Extension](#building-the-extension)
- [When using F5 Debug](#when-using-f5-debug)
- [From Inside VS Code](#from-inside-vs-code)
- [From Command line](#from-command-line)
- [Use of an isolated VS Code environment](#use-of-an-isolated-vs-code-environment)
- [Testing](#testing)
- [Unit tests](#unit-tests)
- [Scenario Tests](#scenario-tests)
- [Scripts](#scripts)
- [`yarn scripts`](#yarn-scripts)
- [`yarn show`](#yarn-show)
- [`yarn clean`](#yarn-clean)
- [`yarn test`](#yarn-test)
- [`yarn code`](#yarn-code)
- [`yarn generate-native-strings`](#yarn-generate-native-strings)
- [`yarn generate-options-schema`](#yarn-generate-options-schema)
- [`yarn copy-walkthrough-media`](#yarn-copy-walkthrough-media)
- [`yarn prep`](#yarn-prep)
- [`yarn lint`](#yarn-lint)
- [`yarn compile`](#yarn-compile)
- [`yarn watch`](#yarn-watch)
- [`yarn verify`](#yarn-verify)
- [`yarn webpack`](#yarn-webpack)
- [`yarn install`](#yarn-install)
## Setup
### Required Tools
* [Node.js](https://nodejs.org/en/download/) v16.*
* Yarn - use `npm install -g yarn` to install
### Setting up the repository
`git clone https://github.com/microsoft/vscode-cpptools.git`
`yarn install`
It's also good practice to run `yarn install` after merging from upstream or switching branches.
## Building the Extension
### When using F5 Debug
The `launch.json` entries now specify a `preLaunchTask` that will build the extension before launching using
the `yarn watch` command, and will wait until the build is ready. The watch command will continue to watch from
that point.
If the extension is already built, the the watch will be very quick.
### From Inside VS Code
There are two tasks that can be run from inside VS Code to build the extension.
When you select `ctrl-shift-b` - there is a `Compile` task and a `Watch` task.
During regular development, you probably want to use the `Watch` task as it will
compile changed files as you save them.
### From Command line
To build the extension from the command line, use the [`yarn compile`](#yarn-compile) command, or
[`yarn watch`](#yarn-watch) to watch for changes and recompile as needed.
<hr>
## Use of an isolated VS Code environment
The scripts for this repository now support running VS Code and the extension in a
completely isolated environment (separate install of VS Code, private extensions and
user folders, etc).
The scripts that install VS Code place it in a `$ENV:TMP/.vscode-test/<UID>` folder where
`<UID>` is a has calculated from the extension folder (this permits multiple checkouts of
the source repository and each gets it's own isolated environment).
The [`test scripts`](#yarn-test) will automatically install and use this isolated environment.
You can invoke VS Code from the command line using the [`yarn code`](#yarn-code) script.
If you want to remove the isolate environment use the `yarn code reset` or `yarn test reset` scripts
to delete the folders and remove all of the configuration files. Next time you use the `yarn test` or
`yarn code` commands, it will reinstall a fresh isolated environment.
The Isolated environment has the theme automatically set to blue so that it is visually distinct from
your normal VS Code environment.
> #### Note
> When debugging the scenario tests from VS Code, it has to use the same VS Code binary
> as the debugger instance, so the isolated environment can't be used.
## Testing
The test architecture has been reorganized and the layout refactored a bit.
``` yaml
test/ : the test folder for all the tests
common/: : infrastructure/common code for tests
scenarios: : contains a folder for each scenario test
<SCENARIONAME>: : a folder for a set of scenario tests
assets/ : the folder that contains the workspace files for the test
# if the assets folder contains a '*.code-workspace' file,
# the test runner will use that for the workspace otherwise
# it will use the assets folder itself as the workspace.
tests/ : location of the VS Code mocha tests for the scenario
# the tests must be in `*.test.ts` files
unit/ : low-level unit tests (not in the VS Code environment)
# the tests must be in `*.test.ts` files
```
To create a new scenario, create a folder in the `scenarios` folder, and add a `assets` and `tests` folder
inside of it.
### Unit tests
Unit tests can be run with the VS Code Test Explorer (install mocha test explorer to enable it).
The Test Explorer allows you to debug into the tests as well.
You can also run the unit tests from the command line (see [`yarn test`](#yarn-test) below)
### Scenario Tests
Scenario tests (which use `@vscode/test-electron`) can be debugged from VS Code, but VS Code requires
that the extension host is the same binary as the debugger, so the isolated environment can't be used.
Selecting the `VS Code Tests` option in the debugger and pressing F5 will prompt for the the scenario to
run the tests for under the debugger.
> #### Note
> There are a few rough cases where the debugging the extension isn't working quite correctly. In
> `MultiRootDeadlockTests` we are getting a deadlock in the `executeCommand` when the debugger is attached.
>
> This is being investigated.
## Scripts
The `package.json` file contains a number of scripts intended to be run via `Yarn`.
A number of the scripts that used to use `gulp` have been extracted and put into the
`.scripts/` folder, and are run directly using `tsnode` -- this makes them easier to
reuse, and doesn't rely on `gulp` and `gulp` plugins.
More of the scripts will be converted out of `gulp` in the future.
<hr>
### `yarn scripts`
> #### `yarn scripts` - shows the commands available in the `package.json`
This shows the commands available in the `scripts` section of the `package.json` file along with their definition
<hr>
### `yarn show`
> #### `yarn show` - shows the files in the repository that are untracked and .gitignored
This shows the files in the repository that are not tracked (i.e. not in .git) and are
ignored by `git` This will not show untracked files that are not ignored (i.e. new files
that you could add to the repository)
> #### `yarn show new` - shows new files that are not git ignored
This shows the files in the repository that are not tracked and are not
ignored by `git`.
<hr>
### `yarn clean`
> #### `yarn clean` - cleans out the `dist` files out of the repository.
Removes all of the files in the `dist` folder (where all the compiled .js files are)
> #### `yarn clean all` - cleans all the untracked/ignored files out of the repository except for `node_modules`
Removes all of the `untracked` and `.gitignored` in the repository except for files in the `node_modules` folder.
(this is useful to reset the repository to a clean state, but not have to reinstall all of the dependencies)
Will not touch any files that could be added to the repo (i.e. new .ts files, etc)
> #### `yarn clean reset` - cleans all the untracked/ignored files out of the repository
Removes all of the `untracked` and `.gitignored` in the repository except.
(this is useful to reset the repository to a clean state)
Will not touch any files that could be added to the repo (i.e. new .ts files, etc)
<hr>
### `yarn test`
> `yarn test` - run just the unit tests
The mocha test runner is invoked for the unit tests. This does not use VS Code in any way.
> `yarn test all` - run all the tests
The unit tests are run, and then each of the scenario test sets are run in turn.
This will install the isolated VS Code environment if it is not already installed.
> `yarn test --scenario=<SCENARIONAME>` - run a single set of scenario tests
> `yarn test <SCENARIONAME>` - run a single set of scenario tests
This will just run the tests for the given scenario. You can pass in the folder name
(in `test/scenarios` or a full path to a folder with `assets` and `tests`)
> `yarn test reset` - remove the isolated VS Code environment
This will completely remove the isolated VS Code environment for this repository,
including cache, extensions, and configuration for the isolated environment.
> `yarn test install` - install the isolated VS Code environment
This installs the isolated VS Code environment if it is not currently installed for this
repository. This is done automatically when running the tests, but can be run manually.
> `yarn test regen` - update the pick lists in `.vscode/launch.json` for any new scenarios.
This adds new entries in the the pick lists in `.vscode/launch.json` to include any new scenarios
that you have added to the `test/scenarios` folder. It will add scenarios that have `assets` and `tests` folders
(and have been compiled at least once). It does not overwrite or update existing entries.
This saves you the effort of having to manually update the launch.json file.
---
### `yarn code`
> #### `yarn code <folder|workspace|scenario>` - run VS Code
This runs the isolated VS Code environment, with the cpptools extension that is built in this repo
You can treat this essentially like using `code` from the command line. Settings can be configured, and
extensions can be installed into the isolated environment, and will be persisted across runs.
Use `yarn code reset` to remove the isolated environment and start fresh.
> `yarn code reset` - remove the isolated VS Code environment
This will completely remove the isolated VS Code environment for this repository,
including cache, extensions, and configuration for the isolated environment.
> `yarn code install` - install the isolated VS Code environment
This installs the isolated VS Code environment if it is not currently installed for this
repository. This is done automatically when running the `yarn code`, but can be run manually.
---
### `yarn generate-native-strings`
> #### `yarn generate-native-strings` - generates the native strings
This used to generate nativeStrings.ts and localized_string_ids.h from ./src/nativeStrings.json
If adding localized strings to the native side, start by adding it to nativeStrings.json and use this to generate the others.
> #### Note
> The use of the `.scripts/common.ts:write()` function ensures that if the contents don't change the file won't be touched
---
### `yarn generate-options-schema`
> #### `yarn generate-options-schema` - generates the options schema
Inserts the options schema into `package.json` from the `tools/OptionsSchema.json` and the `tools/VSSymbolSettings.json` file.
> #### Note
> The use of the `.scripts/common.ts:write()` function ensures that if the contents don't change the file won't be touched
---
### `yarn copy-walkthrough-media`
> #### `yarn copy-walkthrough-media` - copies the walkthrough media
This copies the walkthrough media into the `dist` folder.
> #### Note
> The use of the `.scripts/common.ts:updateFiles()` function ensures that if the contents don't change the files won't be touched
> #### `yarn copy-walkthrough-media watch` - watches for changes and automatically copies the walkthrough media
This will watch for changes to the walkthrough files and automatically copy them across when they change.
---
### `yarn prep`
> #### `yarn prep` - extension preparation
This will call `yarn copy-walkthrough-media`, `yarn generate-native-strings`, `yarn translations-generate` to ensure
that the generated files are up to date.
---
### `yarn lint`
> #### `yarn lint` - lint all the source files (tests, ui, src, and .scripts)
This will lint all the source files and report errors.
> #### `yarn lint --fix` - lint all the source files and auto fix anything it can.
---
### `yarn compile`
> #### `yarn compile` - compile the typescript source code
Runs the typescript compiler on the source code (`test`,`src`,`ui`) and the output is placed in the `dist` folder.
This means we don't use webpack for day-to-day use anymore.
This will also verify that the repository is prepped and tries to prep it if it's not.
---
### `yarn watch`
> #### `yarn watch` - compile the source code and watch for changes
Runs the typescript compiler in watch mode on the source code (`test`,`src`,`ui`) and the output is placed in the `dist` folder.
Any changes to the source files will be automatically compiled when saved.
This will also verify that the repository is prepped and tries to prep it if it's not.
---
### `yarn verify`
> #### `yarn verify [--verbose]` - verifies that the repository is built correctly
Checks for the presence of the compiled files and the prepped files (see [`yarn verify prep`](#yarn-verify))
(no output unless it fails)
> #### `yarn verify prep [--verbose]` - verifies that the repository has been prepped to build
Checks for the presence of the generated loc files and other files that are necessary to build.
(no output unless it fails)
---
### `yarn webpack`
> #### `yarn webpack` - uses webpack to build the extension
This will use webpack to build the extension. This is only necessary when packaging the extension.
---
### `yarn install`
> #### `yarn install` - post `yarn install` steps (runs the `postinstall` script)
Installs the VS Code `*.d.ts` files and then runs `yarn prep`
You should run `yarn install` after merging from upstream or switching branches.
@@ -72,7 +72,7 @@ export class ParsedEnvironmentFile {
// show error message if single lines cannot get parsed
let warning: string | undefined;
if (parseErrors.length !== 0) {
warning = localize("ignoring.lines.in.envfile", "Ignoring non-parseable lines in {0} {1}: ", "envFile", envFile);
warning = localize("ignoring.lines.in.envfile", "Ignoring non-parsable lines in {0} {1}: ", "envFile", envFile);
parseErrors.forEach(function (value, idx, array): void {
warning += "\"" + value + "\"" + ((idx !== array.length - 1) ? ", " : ".");
});
+2 -2
View File
@@ -133,8 +133,8 @@ export class RemoteAttachPicker {
}
return `${outerQuote}${shPrefix}sh -c ${innerQuote}uname && if [ ${parameterBegin}uname -o${parameterEnd} = ${escapedQuote}Toybox${escapedQuote} ] ; ` +
`then ${PsProcessParser.psToyboxCommand} ; elif [ ${parameterBegin}uname${parameterEnd} = ${escapedQuote}Darwin${escapedQuote} ] ; ` +
`then ${PsProcessParser.psLinuxCommand} ; elif [ ${parameterBegin}uname${parameterEnd} = ${escapedQuote}Linux${escapedQuote} ] ; ` +
`then ${PsProcessParser.psToyboxCommand} ; elif [ ${parameterBegin}uname${parameterEnd} = ${escapedQuote}Linux${escapedQuote} ] ; ` +
`then ${PsProcessParser.psLinuxCommand} ; elif [ ${parameterBegin}uname${parameterEnd} = ${escapedQuote}Darwin${escapedQuote} ] ; ` +
`then ${PsProcessParser.psDarwinCommand}; fi${innerQuote}${outerQuote}`;
}
+15 -14
View File
@@ -204,7 +204,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "succeeded": "true" });
if (!resolveByVsCode) {
if ((singleFile || (isDebugPanel && !folder && isExistingTask))) {
if (singleFile || (isDebugPanel && !folder && isExistingTask)) {
await this.resolvePreLaunchTask(config, configMode);
config.preLaunchTask = undefined;
} else {
@@ -384,7 +384,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
await this.loadDetectedTasks();
// Remove the tasks that are already configured once in tasks.json.
const dedupDetectedBuildTasks: CppBuildTask[] = DebugConfigurationProvider.detectedBuildTasks.filter(taskDetected =>
(!configuredBuildTasks.some(taskJson => (taskJson.definition.label === taskDetected.definition.label))));
!configuredBuildTasks.some(taskJson => taskJson.definition.label === taskDetected.definition.label));
buildTasks = buildTasks.concat(configuredBuildTasks, dedupDetectedBuildTasks);
// Filter out build tasks that don't match the currently selected debug configuration type.
@@ -419,7 +419,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Absolute path, just check if it exists
await util.checkFileExists(compilerPath) :
// Non-absolute. Check on $PATH
((await util.whichAsync(compilerPath)) !== undefined);
(await util.whichAsync(compilerPath) !== undefined);
if (!compilerPathExists) {
logger.getOutputChannelLogger().appendLine(localize('compiler.path.not.exists', "Unable to find {0}. {1} task is ignored.", compilerPath, definition.label));
}
@@ -442,7 +442,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
newConfig.detail = localize("pre.Launch.Task", "preLaunchTask: {0}", task.name);
newConfig.taskDetail = task.detail;
newConfig.taskStatus = task.existing ?
((task.name === DebugConfigurationProvider.recentBuildTaskLabelStr) ? TaskStatus.recentlyUsed : TaskStatus.configured) :
(task.name === DebugConfigurationProvider.recentBuildTaskLabelStr) ? TaskStatus.recentlyUsed : TaskStatus.configured :
TaskStatus.detected;
if (task.isDefault) {
newConfig.isDefault = true;
@@ -484,11 +484,11 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Check if debuggerPath exists.
if (await util.checkFileExists(debuggerPath)) {
newConfig.miDebuggerPath = debuggerPath;
} else if ((await util.whichAsync(debuggerName)) !== undefined) {
} else if (await util.whichAsync(debuggerName) !== undefined) {
// Check if debuggerName exists on $PATH
newConfig.miDebuggerPath = debuggerName;
} else {
// Try the usr path for non-windows platforms.
// Try the usr path for non-Windows platforms.
const usrDebuggerPath: string = path.join("/usr", "bin", debuggerName);
if (!isWindows && await util.checkFileExists(usrDebuggerPath)) {
newConfig.miDebuggerPath = usrDebuggerPath;
@@ -661,6 +661,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const newSourceFileMapSource: string = util.resolveVariables(sourceFileMapSource, undefined);
if (sourceFileMapSource !== newSourceFileMapSource) {
message = "\t" + localize("replacing.sourcepath", "Replacing {0} '{1}' with '{2}'.", "sourcePath", sourceFileMapSource, newSourceFileMapSource);
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete config.sourceFileMap[sourceFileMapSource];
source = newSourceFileMapSource;
}
@@ -669,7 +670,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const newSourceFileMapTarget: string = util.resolveVariables(sourceFileMapTarget, undefined);
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += message ? ' ' : '\t';
message += localize("replacing.targetpath", "Replacing {0} '{1}' with '{2}'.", "targetPath", sourceFileMapTarget, newSourceFileMapTarget);
target = newSourceFileMapTarget;
}
@@ -679,7 +680,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
if (sourceFileMapTarget !== newSourceFileMapTarget) {
// Add a space if source was changed, else just tab the target message.
message += (message ? ' ' : '\t');
message += message ? ' ' : '\t';
message += localize("replacing.editorPath", "Replacing {0} '{1}' with '{2}'.", "editorPath", sourceFileMapTarget, newSourceFileMapTarget["editorPath"]);
target = newSourceFileMapTarget;
}
@@ -741,7 +742,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
private findDefaultConfig(configs: CppDebugConfiguration[]): CppDebugConfiguration[] {
// eslint-disable-next-line no-prototype-builtins
return configs.filter((config: CppDebugConfiguration) => (config.hasOwnProperty("isDefault") && config.isDefault));
return configs.filter((config: CppDebugConfiguration) => config.hasOwnProperty("isDefault") && config.isDefault);
}
private async isExistingTask(config: CppDebugConfiguration, folder?: vscode.WorkspaceFolder): Promise<boolean> {
@@ -812,7 +813,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
return item;
}));
}
detailedConfigs = detailedConfigs.filter((config: any) => (config.name && config.request === "launch" && type ? (config.type === type) : true));
detailedConfigs = detailedConfigs.filter((config: any) => config.name && config.request === "launch" && type ? (config.type === type) : true);
return detailedConfigs;
}
@@ -839,7 +840,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
const rawLaunchJson: any = await this.getRawLaunchJson();
if (!rawLaunchJson.configurations) {
rawLaunchJson.configurations = new Array();
rawLaunchJson.configurations = [];
}
if (!rawLaunchJson.version) {
rawLaunchJson.version = "2.0.0";
@@ -914,7 +915,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// If the configs are coming from workspace or global settings and the task is not found in tasks.json, let that to be resolved by VsCode.
if (selectedConfig.preLaunchTask && selectedConfig.configSource &&
(selectedConfig.configSource === ConfigSource.global || selectedConfig.configSource === ConfigSource.workspace) &&
!(await this.isExistingTask(selectedConfig))) {
!await this.isExistingTask(selectedConfig)) {
folder = undefined;
}
selectedConfig.debugType = debugModeOn ? DebugType.debug : DebugType.run;
@@ -950,7 +951,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
} else {
let sortedItems: ConfigMenu[] = [];
// Find the recently used task and place it at the top of quickpick list.
const recentTask: ConfigMenu[] = items.filter(item => (item.configuration.preLaunchTask && item.configuration.preLaunchTask === DebugConfigurationProvider.recentBuildTaskLabelStr));
const recentTask: ConfigMenu[] = items.filter(item => item.configuration.preLaunchTask && item.configuration.preLaunchTask === DebugConfigurationProvider.recentBuildTaskLabelStr);
if (recentTask.length !== 0 && recentTask[0].detail !== TaskStatus.detected) {
recentTask[0].detail = TaskStatus.recentlyUsed;
sortedItems.push(recentTask[0]);
@@ -960,7 +961,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
sortedItems = sortedItems.concat(items.filter(item => item.detail === undefined));
selection = await vscode.window.showQuickPick(this.localizeConfigDetail(sortedItems), {
placeHolder: (items.length === 0 ? localize("no.compiler.found", "No compiler found") : localize("select.debug.configuration", "Select a debug configuration"))
placeHolder: items.length === 0 ? localize("no.compiler.found", "No compiler found") : localize("select.debug.configuration", "Select a debug configuration")
});
}
if (selection && this.isClConfiguration(selection.configuration.name) && this.showErrorIfClNotAvailable(selection.configuration.name)) {
+7 -7
View File
@@ -26,8 +26,8 @@ export enum DebuggerType {
}
export enum DebuggerEvent {
debugPanel = "debugPanel", // F5 or "Run and Debug" Panel
playButton = "playButton", // "Run and Debug" play button
debugPanel = "debugPanel", // F5 or "Run and Debug" Panel
playButton = "playButton", // "Run and Debug" play button
addConfigGear = "AddConfigGear"
}
@@ -35,14 +35,14 @@ export enum TaskStatus {
recentlyUsed = "Recently Used Task", // A configured task that has been used recently.
configured = "Configured Task", // The tasks that are configured in tasks.json file.
detected = "Detected Task" // The tasks that are available based on detected compilers.
detected = "Detected Task" // The tasks that are available based on detected compilers.
}
export enum ConfigSource {
singleFile = "singleFile", // a debug config defined for a single mode file
workspaceFolder = "workspaceFolder", // a debug config defined in launch.json
workspace = "workspace", // a debug config defined in workspace level
global = "global", // a debug config defined in user level
singleFile = "singleFile", // a debug config defined for a single mode file
workspaceFolder = "workspaceFolder", // a debug config defined in launch.json
workspace = "workspace", // a debug config defined in workspace level
global = "global", // a debug config defined in user level
unknown = "unknown"
}
@@ -26,9 +26,6 @@ abstract class AbstractDebugAdapterDescriptorFactory implements vscode.DebugAdap
}
export class CppdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDescriptorFactory {
constructor(context: vscode.ExtensionContext) {
super(context);
}
async createDebugAdapterDescriptor(_session: vscode.DebugSession, _executable?: vscode.DebugAdapterExecutable): Promise<vscode.DebugAdapterDescriptor> {
const adapter: string = "./debugAdapters/bin/OpenDebugAD7" + (os.platform() === 'win32' ? ".exe" : "");
@@ -40,13 +37,10 @@ export class CppdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDes
}
export class CppvsdbgDebugAdapterDescriptorFactory extends AbstractDebugAdapterDescriptorFactory {
constructor(context: vscode.ExtensionContext) {
super(context);
}
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 avaliable for non-Windows machines.", "cppvsdbg"));
void vscode.window.showErrorMessage(localize("debugger.not.available", "Debugger type '{0}' is not available for non-Windows machines.", "cppvsdbg"));
return null;
} else {
return new vscode.DebugAdapterExecutable(
+9 -9
View File
@@ -8,14 +8,14 @@ import * as os from 'os';
import { Configuration } from 'ssh-config';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { pathAccessible } from '../common';
import { CppSettings } from '../LanguageServer/settings';
import { getSshChannel } from '../logger';
import { BaseNode, addSshTargetCmd, refreshCppSshTargetsViewCmd } from '../SSH/TargetsView/common';
import { SshTargetsProvider, getActiveSshTarget, initializeSshTargets, selectSshTarget } from '../SSH/TargetsView/sshTargetsProvider';
import { TargetLeafNode, setActiveSshTarget } from '../SSH/TargetsView/targetNodes';
import { sshCommandToConfig } from '../SSH/sshCommandToConfig';
import { getSshConfiguration, getSshConfigurationFiles, parseFailures, writeSshConfiguration } from '../SSH/sshHosts';
import { addSshTargetCmd, BaseNode, refreshCppSshTargetsViewCmd } from '../SSH/TargetsView/common';
import { getActiveSshTarget, initializeSshTargets, selectSshTarget, SshTargetsProvider } from '../SSH/TargetsView/sshTargetsProvider';
import { setActiveSshTarget, TargetLeafNode } from '../SSH/TargetsView/targetNodes';
import { pathAccessible } from '../common';
import { getSshChannel } from '../logger';
import { AttachItemsProvider, AttachPicker, RemoteAttachPicker } from './attachToProcess';
import { ConfigurationAssetProviderFactory, ConfigurationSnippetProvider, DebugConfigurationProvider, IConfigurationAssetProvider } from './configurationProvider';
import { DebuggerType } from './configurations';
@@ -42,7 +42,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
const assetProvider: IConfigurationAssetProvider = ConfigurationAssetProviderFactory.getConfigurationProvider();
// Register DebugConfigurationProviders for "Run and Debug" in Debug Panel.
// On windows platforms, the cppvsdbg debugger will also be registered for initial configurations.
// On Windows platforms, the cppvsdbg debugger will also be registered for initial configurations.
let cppVsDebugProvider: DebugConfigurationProvider | null = null;
if (os.platform() === 'win32') {
cppVsDebugProvider = new DebugConfigurationProvider(assetProvider, DebuggerType.cppvsdbg);
@@ -107,7 +107,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
disposables.push(sshTargetsProvider);
// Decide if we should show the SSH Targets View.
sshTargetsViewSetting = (new CppSettings()).sshTargetsView;
sshTargetsViewSetting = new CppSettings().sshTargetsView;
// Active SSH Target initialized in initializeSshTargets()
if (sshTargetsViewSetting === 'enabled' || (sshTargetsViewSetting === 'default' && await getActiveSshTarget(false))) {
// Don't wait
@@ -116,7 +116,7 @@ export async function initialize(context: vscode.ExtensionContext): Promise<void
disposables.push(vscode.workspace.onDidChangeConfiguration(async (e: vscode.ConfigurationChangeEvent) => {
if (e.affectsConfiguration('C_Cpp.sshTargetsView')) {
sshTargetsViewSetting = (new CppSettings()).sshTargetsView;
sshTargetsViewSetting = new CppSettings().sshTargetsView;
if (sshTargetsViewSetting === 'enabled' || (sshTargetsViewSetting === 'default' && await getActiveSshTarget(false))) {
await enableSshTargetsView();
} else if (sshTargetsViewSetting === 'disabled') {
@@ -215,7 +215,7 @@ async function addSshTargetImpl(): Promise<string> {
async function removeSshTargetImpl(node: TargetLeafNode): Promise<boolean> {
const labelYes: string = localize('yes', 'Yes');
const labelNo: string = localize('no', 'No');
const confirm: string | undefined = await vscode.window.showInformationMessage(localize('ssh.target.delete.confirmation', 'Are you sure you want to permanamtly delete "{0}"?', node.name), labelYes, labelNo);
const confirm: string | undefined = await vscode.window.showInformationMessage(localize('ssh.target.delete.confirmation', 'Are you sure you want to permanently delete "{0}"?', node.name), labelYes, labelNo);
if (!confirm || confirm === labelNo) {
return false;
}
+1 -1
View File
@@ -12,7 +12,7 @@ export class ArchitectureReplacer {
public static checkAndReplaceWSLPipeProgram(pipeProgramStr: string, expectedArch: ArchType): string | undefined {
let replacedPipeProgram: string | undefined;
const winDir: string | undefined = process.env.WINDIR ? process.env.WINDIR.toLowerCase() : undefined;
const winDirAltDirSep: string | undefined = process.env.WINDIR ? process.env.WINDIR.replace('\\', '/').toLowerCase() : undefined;
const winDirAltDirSep: string | undefined = process.env.WINDIR ? process.env.WINDIR.replace('\\', '/').toLowerCase() : undefined;
const winDirEnv: string = "${env:windir}";
if (winDir && winDirAltDirSep && (pipeProgramStr.indexOf(winDir) === 0 || pipeProgramStr.indexOf(winDirAltDirSep) === 0 || pipeProgramStr.indexOf(winDirEnv) === 0)) {
@@ -4,6 +4,7 @@
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import { DefaultClient } from '../client';
import {
CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisAllFixes, codeAnalysisCodeToFixes, codeAnalysisFileToCodeActions
@@ -12,6 +13,9 @@ import { LocalizeStringParams, getLocalizedString } from '../localization';
import { CppSettings } from '../settings';
import { makeVscodeRange } from '../utils';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
interface GetCodeActionsRequestParams {
uri: string;
range: Range;
@@ -24,17 +28,13 @@ interface CodeActionCommand {
edit?: TextEdit;
uri?: string;
range?: Range;
disabledReason?: string;
}
interface GetCodeActionsResult {
commands: CodeActionCommand[];
}
export interface CreateDeclDefnCommandArguments {
sender: string;
range: Range;
}
export const GetCodeActionsRequest: RequestType<GetCodeActionsRequestParams, GetCodeActionsResult, void> =
new RequestType<GetCodeActionsRequestParams, GetCodeActionsResult, void>('cpptools/getCodeActions');
@@ -44,6 +44,10 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
this.client = client;
}
private static inlineMacroKind: vscode.CodeActionKind = vscode.CodeActionKind.RefactorInline.append("macro");
private static extractToFunctionKind: vscode.CodeActionKind = vscode.CodeActionKind.RefactorExtract.append("function");
private static expandSelectionKind: vscode.CodeActionKind = CodeActionProvider.extractToFunctionKind.append("expandSelection");
public async provideCodeActions(document: vscode.TextDocument, range: vscode.Range | vscode.Selection,
context: vscode.CodeActionContext, token: vscode.CancellationToken): Promise<(vscode.Command | vscode.CodeAction)[]> {
await this.client.ready;
@@ -66,7 +70,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
uri: document.uri.toString()
};
const response: GetCodeActionsResult = await this.client.languageClient.sendRequest(
let response: GetCodeActionsResult = await this.client.languageClient.sendRequest(
GetCodeActionsRequest, params, token);
const resultCodeActions: vscode.CodeAction[] = [];
@@ -84,17 +88,20 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
this.client.configuration.CurrentConfiguration?.compilerPathInCppPropertiesJson !== undefined ||
!!this.client.configuration.CurrentConfiguration?.compileCommandsInCppPropertiesJson ||
!!this.client.configuration.CurrentConfiguration?.configurationProviderInCppPropertiesJson;
const hasExperimentalFeatures: boolean = new CppSettings().experimentalFeatures ?? false;
// Convert to vscode.CodeAction array
response.commands.forEach((command) => {
let hasInlineMacro: boolean = false;
const processCommand = (command: CodeActionCommand) => {
let title: string = getLocalizedString(command.localizeStringParams);
let wsEdit: vscode.WorkspaceEdit | undefined;
let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix;
if (command.edit) {
// Inline macro feature.
codeActionKind = vscode.CodeActionKind.RefactorInline;
codeActionKind = CodeActionProvider.inlineMacroKind;
wsEdit = new vscode.WorkspaceEdit();
wsEdit.replace(document.uri, makeVscodeRange(command.edit.range), command.edit.newText);
hasInlineMacro = true;
} else if (command.command === "C_Cpp.RemoveAllCodeAnalysisProblems" && command.uri !== undefined) {
// The "RemoveAll" message is sent for all code analysis squiggles.
const vsCodeRange: vscode.Range = makeVscodeRange(r);
@@ -173,7 +180,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
}
if (showClear !== "None") {
let showClearAllAvailable: boolean = false;
if ((codeActionDiagnosticInfo.length > 1 || codeAnalysisFileToCodeActions.size > 1)) {
if (codeActionDiagnosticInfo.length > 1 || codeAnalysisFileToCodeActions.size > 1) {
showClearAllAvailable = true;
}
if (!showClearAllAvailable || showClear !== "AllOnly") {
@@ -188,12 +195,8 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
return;
} else if ((command.command === 'C_Cpp.CreateDeclarationOrDefinition' || command.command === 'C_Cpp.CopyDeclarationOrDefinition')
&& (command.arguments ?? []).length === 0 && command.range !== undefined) {
const args: CreateDeclDefnCommandArguments = {
sender: 'codeAction',
range: command.range
};
command.arguments = [];
command.arguments.push(args);
command.arguments.push({ sender: 'codeAction', range: command.range });
} else if (command.command === "C_Cpp.SelectIntelliSenseConfiguration") {
command.arguments = ['codeAction'];
hasSelectIntelliSenseConfiguration = true;
@@ -206,6 +209,20 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
} else {
return;
}
} else if (command.command === "C_Cpp.ExtractToFunction" ||
command.command === "C_Cpp.ExtractToMemberFunction") {
if (!hasExperimentalFeatures) {
return;
}
codeActionKind = CodeActionProvider.extractToFunctionKind;
} else if (command.command === "C_Cpp.ExtractToFreeFunction") {
// TODO: https://github.com/microsoft/vscode-cpptools/issues/11473 needs to be fixed.
return;
} else if (command.command === "C_Cpp.ExpandSelection") {
if (!hasExperimentalFeatures) {
return;
}
codeActionKind = CodeActionProvider.expandSelectionKind;
}
const vscodeCodeAction: vscode.CodeAction = {
title: title,
@@ -215,10 +232,51 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
arguments: command.arguments
},
edit: wsEdit,
kind: codeActionKind
kind: codeActionKind,
disabled: command.disabledReason ? { reason: command.disabledReason } : undefined
};
resultCodeActions.push(vscodeCodeAction);
});
};
response.commands.forEach(processCommand);
// If the refactor.inline.macro code action is specifically invoked by the user,
// then force a hover to ensure that the "Expands to" info is available.
if (!hasInlineMacro && context.only?.value === "refactor.inline.macro") {
const processInlineMacro = async (): Promise<boolean> => {
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (!editor) {
return false;
}
const result: vscode.Hover[] = (await vscode.commands.executeCommand('vscode.executeHoverProvider', document.uri, range.start)) as vscode.Hover[];
if (result.length === 0) {
return false;
}
const hoverResult: vscode.MarkdownString = result[0].contents[0] as vscode.MarkdownString;
if (!hoverResult.value.includes(localize("expands.to", "Expands to:"))) {
return false;
}
response = await this.client.languageClient.sendRequest(GetCodeActionsRequest, params, token);
if (token.isCancellationRequested || response.commands === undefined) {
return false;
}
for (const command of response.commands) {
if (command.edit) {
processCommand(command);
return true;
}
}
return false;
};
if (!await processInlineMacro()) {
const disabledCodeAction: vscode.CodeAction = {
title: localize({ key: "inline.macro", comment: ["'Inline' is a command and not an adjective, i.e. like 'Expand macro'."] }, "Inline macro"),
kind: CodeActionProvider.inlineMacroKind,
disabled: { reason: localize("inline.macro.not.available", "Inline macro is not available at this location.") }
};
resultCodeActions.push(disabledCodeAction);
}
}
return resultCodeActions;
}
}
@@ -13,7 +13,8 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange
this.client = client;
}
public async provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range, options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
public async provideDocumentRangeFormattingEdits(document: vscode.TextDocument, range: vscode.Range,
options: vscode.FormattingOptions, token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
const settings: CppSettings = new CppSettings(vscode.workspace.getWorkspaceFolder(document.uri)?.uri);
if (settings.formattingEngine === "disabled") {
return [];
@@ -58,4 +59,12 @@ export class DocumentRangeFormattingEditProvider implements vscode.DocumentRange
return configCallBack(editorConfigSettings);
}
}
// TODO: This is needed for correct Extract to function formatting.
/*
public async provideDocumentRangesFormattingEdits(_document: vscode.TextDocument, _ranges: vscode.Range[],
_options: vscode.FormattingOptions, _token: vscode.CancellationToken): Promise<vscode.TextEdit[]> {
return [];
}
*/
}
@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { Position, RequestType } from 'vscode-languageclient';
import { DefaultClient, workspaceReferences } from '../client';
import { CancellationSender, ReferenceInfo, ReferencesParams, ReferencesResult, ReferenceType } from '../references';
import { CancellationSender, ReferenceInfo, ReferenceType, ReferencesParams, ReferencesResult } from '../references';
const FindAllReferencesRequest: RequestType<ReferencesParams, ReferencesResult, void> =
new RequestType<ReferencesParams, ReferencesResult, void>('cpptools/findAllReferences');
@@ -37,7 +37,6 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
const response: ReferencesResult = await this.client.languageClient.sendRequest(FindAllReferencesRequest, params, cancelSource.token);
// Reset anything that can be cleared before processing the result.
// Note: ReferencesManager.resetReferences is called in ReferencesManager.showResultsInPanelView
workspaceReferences.resetProgressBar();
cancellationTokenListener.dispose();
requestCanceledListener.dispose();
@@ -48,8 +47,9 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
// "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 (response.referenceInfos.length !== 0) {
} else if (response.referenceInfos.length > 0) {
response.referenceInfos.forEach((referenceInfo: ReferenceInfo) => {
if (referenceInfo.type === ReferenceType.Confirmed) {
const uri: vscode.Uri = vscode.Uri.file(referenceInfo.file);
@@ -60,7 +60,10 @@ export class FindAllReferencesProvider implements vscode.ReferenceProvider {
});
// Display other reference types in panel or channel view.
// Note: ReferencesManager.resetReferences is called in ReferencesManager.showResultsInPanelView
workspaceReferences.showResultsInPanelView(response);
} else {
workspaceReferences.resetReferences();
}
return locationsResult;
@@ -104,7 +104,7 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
const inlayHint: vscode.InlayHint = new vscode.InlayHint(
new vscode.Position(hint.position.line, hint.position.character +
(showOnLeft ? 0 : hint.identifierLength)),
(showOnLeft ? hint.label : ": " + hint.label),
showOnLeft ? hint.label : ": " + hint.label,
vscode.InlayHintKind.Type);
inlayHint.paddingRight = showOnLeft || hint.rightPadding;
inlayHint.paddingLeft = showOnLeft && hint.leftPadding;
@@ -7,7 +7,7 @@ import { Position, RequestType } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import * as util from '../../common';
import { DefaultClient, workspaceReferences } from '../client';
import { CancellationSender, getReferenceItemIconPath, getReferenceTagString, ReferencesParams, ReferencesResult, ReferenceType } from '../references';
import { CancellationSender, ReferenceType, ReferencesParams, ReferencesResult, getReferenceItemIconPath, getReferenceTagString } from '../references';
import { CppSettings } from '../settings';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
@@ -23,7 +23,17 @@ export class RenameProvider implements vscode.RenameProvider {
this.client = client;
}
public async provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string, _token: vscode.CancellationToken): Promise<vscode.WorkspaceEdit | undefined> {
public async provideRenameEdits(document: vscode.TextDocument, position: vscode.Position, newName: string, _token: vscode.CancellationToken): Promise<vscode.WorkspaceEdit | undefined> {
// Bypass the normal rename processing during Extract to function,
// since we already know the locations of the required edits.
if (this.client.renameDataForExtractToFunction.length > 0) {
const workspaceEditResult: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const renameData of this.client.renameDataForExtractToFunction) {
workspaceEditResult.replace(renameData.uri, renameData.range, newName);
}
this.client.renameDataForExtractToFunction = [];
return workspaceEditResult;
}
await this.client.ready;
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
File diff suppressed because it is too large Load Diff
@@ -101,7 +101,7 @@ export class ClientCollection {
public checkOwnership(client: cpptools.Client, document: vscode.TextDocument): boolean {
return (this.getClientFor(document.uri) === client);
return this.getClientFor(document.uri) === client;
}
/**
@@ -154,7 +154,7 @@ export class ClientCollection {
const path: string = util.asFolder(folder.uri);
const client: cpptools.Client | undefined = this.languageClients.get(path);
if (client) {
this.languageClients.delete(path); // Do this first so that we don't iterate on it during the ownership transfer process.
this.languageClients.delete(path); // Do this first so that we don't iterate on it during the ownership transfer process.
// Transfer ownership of the client's documents to another client.
// (this includes calling textDocument/didOpen on the new client so that the server knows it's open too)
+26 -26
View File
@@ -8,7 +8,7 @@ import { LanguageClient, NotificationType, Range } from 'vscode-languageclient/n
import * as nls from 'vscode-nls';
import { Location, WorkspaceEdit } from './commonTypes';
import { CppSourceStr } from './extension';
import { getLocalizedString, LocalizeStringParams } from './localization';
import { LocalizeStringParams, getLocalizedString } from './localization';
import { CppSettings } from './settings';
import { makeVscodeLocation, makeVscodeRange, makeVscodeTextEdits, rangeEquals } from './utils';
@@ -74,7 +74,7 @@ interface CodeActionAllInfo {
interface CodeAnalysisDiagnosticRelatedInformation {
location: Location;
message: string;
workspaceEdit?: WorkspaceEdit;
workspaceEdits?: WorkspaceEdit[];
}
interface CodeAnalysisDiagnostic {
@@ -83,7 +83,7 @@ interface CodeAnalysisDiagnostic {
severity: vscode.DiagnosticSeverity;
localizeStringParams: LocalizeStringParams;
relatedInformation?: CodeAnalysisDiagnosticRelatedInformation[];
workspaceEdit?: WorkspaceEdit;
workspaceEdits?: WorkspaceEdit[];
}
interface CodeAnalysisDiagnosticIdentifier {
@@ -118,7 +118,7 @@ export const codeAnalysisCodeToFixes: Map<string, CodeActionCodeInfo> = new Map<
export const codeAnalysisAllFixes: CodeActionAllInfo = {
version: 0,
fixAllCodeAction: {
title: localize("fix_all_code_analysis_problems", "Fix all code analysis problems"),
title: localize("fix.all.code.analysis.problems", "Fix all code analysis problems"),
command: {
title: 'FixAllCodeAnalysisProblems',
command: 'C_Cpp.FixAllCodeAnalysisProblems',
@@ -127,7 +127,7 @@ export const codeAnalysisAllFixes: CodeActionAllInfo = {
kind: vscode.CodeActionKind.QuickFix
},
removeAllCodeAction: {
title: localize("clear_all_code_analysis_problems", "Clear all code analysis problems"),
title: localize("clear.all.code.analysis.problems", "Clear all code analysis problems"),
command: { title: "RemoveAllCodeAnalysisProblems", command: "C_Cpp.RemoveAllCodeAnalysisProblems" },
kind: vscode.CodeActionKind.QuickFix
}
@@ -175,7 +175,7 @@ function rebuildCodeAnalysisCodeAndAllFixes(): void {
}
++numFixTypes;
codeToFixes[1].fixAllTypeCodeAction = {
title: localize("fix_all_type_problems", "Fix all {0} problems", codeToFixes[0]),
title: localize("fix.all.type.problems", "Fix all {0} problems", codeToFixes[0]),
command: {
title: 'FixAllTypeCodeAnalysisProblems',
command: 'C_Cpp.FixAllTypeCodeAnalysisProblems',
@@ -187,7 +187,7 @@ function rebuildCodeAnalysisCodeAndAllFixes(): void {
if (new CppSettings().clangTidyCodeActionShowDisable) {
codeToFixes[1].disableAllTypeCodeAction = {
title: localize("disable_all_type_problems", "Disable all {0} problems", codeToFixes[0]),
title: localize("disable.all.type.problems", "Disable all {0} problems", codeToFixes[0]),
command: {
title: 'DisableAllTypeCodeAnalysisProblems',
command: 'C_Cpp.DisableAllTypeCodeAnalysisProblems',
@@ -201,7 +201,7 @@ function rebuildCodeAnalysisCodeAndAllFixes(): void {
if (new CppSettings().clangTidyCodeActionShowClear !== "None") {
codeToFixes[1].removeAllTypeCodeAction = {
title: localize("clear_all_type_problems", "Clear all {0} problems", codeToFixes[0]),
title: localize("clear.all.type.problems", "Clear all {0} problems", codeToFixes[0]),
command: {
title: 'RemoveAllTypeCodeAnalysisProblems',
command: 'C_Cpp.RemoveCodeAnalysisProblems',
@@ -265,7 +265,7 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
range: makeVscodeRange(identifier.range),
code: identifier.code,
removeCodeAction: {
title: localize("clear_this_problem", "Clear this {0} problem", d.code),
title: localize("clear.this.problem", "Clear this {0} problem", d.code),
command: {
title: 'RemoveCodeAnalysisProblems',
command: 'C_Cpp.RemoveCodeAnalysisProblems',
@@ -274,18 +274,18 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
kind: vscode.CodeActionKind.QuickFix
}
};
const workspaceEdit: CodeActionWorkspaceEdit = {};
if (d.workspaceEdit) {
workspaceEdit.workspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(d.workspaceEdit.changes)) {
workspaceEdit.workspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
const codeActionWorkspaceEdit: CodeActionWorkspaceEdit = {};
if (d.workspaceEdits) {
codeActionWorkspaceEdit.workspaceEdit = new vscode.WorkspaceEdit();
for (const workspaceEdit of d.workspaceEdits) {
codeActionWorkspaceEdit.workspaceEdit.set(vscode.Uri.parse(workspaceEdit.file, true), makeVscodeTextEdits(workspaceEdit.edits));
}
const fixThisCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
title: localize("fix.this.problem", "Fix this {0} problem", d.code),
command: {
title: 'FixThisCodeAnalysisProblem',
command: 'C_Cpp.FixThisCodeAnalysisProblem',
arguments: [ nextVersion, workspaceEdit.workspaceEdit, true, [ identifiersAndUri ] ]
arguments: [ nextVersion, codeActionWorkspaceEdit.workspaceEdit, true, [ identifiersAndUri ] ]
},
kind: vscode.CodeActionKind.QuickFix
};
@@ -297,25 +297,25 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
const rootAndRelatedWorkspaceEdits: CodeActionWorkspaceEdit[] = [];
const rootAndRelatedIdentifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
rootAndRelatedIdentifiersAndUris.push(identifiersAndUri);
if (workspaceEdit.workspaceEdit !== undefined) {
rootAndRelatedWorkspaceEdits.push(workspaceEdit);
if (codeActionWorkspaceEdit.workspaceEdit !== undefined) {
rootAndRelatedWorkspaceEdits.push(codeActionWorkspaceEdit);
}
if (d.relatedInformation) {
diagnostic.relatedInformation = [];
for (const info of d.relatedInformation) {
diagnostic.relatedInformation.push(new vscode.DiagnosticRelatedInformation(makeVscodeLocation(info.location), info.message));
if (info.workspaceEdit === undefined) {
if (info.workspaceEdits === undefined) {
continue;
}
const relatedWorkspaceEdit: vscode.WorkspaceEdit = new vscode.WorkspaceEdit();
for (const [uriStr, edits] of Object.entries(info.workspaceEdit.changes)) {
relatedWorkspaceEdit.set(vscode.Uri.parse(uriStr, true), makeVscodeTextEdits(edits));
for (const workspaceEdit of info.workspaceEdits) {
relatedWorkspaceEdit.set(vscode.Uri.parse(workspaceEdit.file, true), makeVscodeTextEdits(workspaceEdit.edits));
}
const relatedIdentifier: CodeAnalysisDiagnosticIdentifier = { range: info.location.range, code: d.code };
const relatedIdentifiersAndUri: CodeAnalysisDiagnosticIdentifiersAndUri = {
uri: info.location.uri, identifiers: [ relatedIdentifier ] };
const relatedCodeAction: vscode.CodeAction = {
title: localize("fix_this_problem", "Fix this {0} problem", d.code),
title: localize("fix.this.problem", "Fix this {0} problem", d.code),
command: {
title: 'FixThisCodeAnalysisProblem',
command: 'C_Cpp.FixThisCodeAnalysisProblem',
@@ -378,13 +378,13 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
docPage = `checks${checksGroup}/${checksPage}.html`;
}
// TODO: This should be checking the clang-tidy version used to better support usage of older versions.
const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/16.0.0/tools/clang/tools/extra/docs/clang-tidy/${docPage}`);
const primaryDocUri: vscode.Uri = vscode.Uri.parse(`https://releases.llvm.org/17.0.1/tools/clang/tools/extra/docs/clang-tidy/${docPage}`);
diagnostic.code = { value: identifier.code, target: primaryDocUri };
if (new CppSettings().clangTidyCodeActionShowDocumentation) {
if (codeActionCodeInfo.docCodeAction === undefined) {
codeActionCodeInfo.docCodeAction = {
title: localize("show_documentation_for", "Show documentation for {0}", primaryCode),
title: localize("show.documentation.for", "Show documentation for {0}", primaryCode),
command: {
title: 'ShowDocumentation',
command: 'C_Cpp.ShowCodeAnalysisDocumentation',
@@ -512,8 +512,8 @@ export function removeCodeAnalysisProblems(identifiersAndUris: CodeAnalysisDiagn
const newDiagnostics: vscode.Diagnostic[] = [];
for (const diagnostic of diagnostics) {
const code: string = typeof diagnostic.code === "string" ? diagnostic.code :
(typeof diagnostic.code === "object" && typeof diagnostic.code.value === "string" ?
diagnostic.code.value : "");
typeof diagnostic.code === "object" && typeof diagnostic.code.value === "string" ?
diagnostic.code.value : "";
let removed: boolean = false;
for (const identifier of identifiersAndUri.identifiers) {
if (code !== identifier.code || !rangeEquals(diagnostic.range, identifier.range)) {
+2 -1
View File
@@ -17,5 +17,6 @@ export interface TextEdit {
}
export interface WorkspaceEdit {
changes: { [uri: string]: TextEdit[] };
file: string;
edits: TextEdit[];
}
+24 -17
View File
@@ -494,7 +494,7 @@ export class CppProperties {
for (const [dep, execCmd] of nodeAddonMap) {
if (dep in packageJson.dependencies) {
try {
let stdout: string | void = await util.execChildProcess(execCmd, rootPath);
let stdout: string = await util.execChildProcess(execCmd, rootPath);
if (!stdout) {
continue;
}
@@ -595,10 +595,10 @@ export class CppProperties {
const settings: CppSettings = new CppSettings(this.rootUri);
const compilerPathAndArgs: util.CompilerPathAndArgs = util.extractCompilerPathAndArgs(!!settings.legacyCompilerArgsBehavior, resolvedCompilerPath);
const isValid: boolean = ((compilerPathAndArgs.compilerName.toLowerCase() === "cl.exe" || compilerPathAndArgs.compilerName.toLowerCase() === "cl") === configuration.intelliSenseMode.includes("msvc")
const isValid: boolean = (compilerPathAndArgs.compilerName.toLowerCase() === "cl.exe" || compilerPathAndArgs.compilerName.toLowerCase() === "cl") === configuration.intelliSenseMode.includes("msvc")
// We can't necessarily determine what host compiler nvcc will use, without parsing command line args (i.e. for -ccbin)
// to determine if the user has set it to something other than the default. So, we don't squiggle IntelliSenseMode when using nvcc.
|| (compilerPathAndArgs.compilerName.toLowerCase() === "nvcc.exe") || (compilerPathAndArgs.compilerName.toLowerCase() === "nvcc"));
|| (compilerPathAndArgs.compilerName.toLowerCase() === "nvcc.exe") || (compilerPathAndArgs.compilerName.toLowerCase() === "nvcc");
if (isValid) {
return "";
} else {
@@ -762,8 +762,14 @@ export class CppProperties {
}
paths = this.resolveDefaults(paths, defaultValue);
paths.forEach(entry => {
const entries: string[] = util.resolveVariables(entry, env).split(util.envDelimiter).map(e => glob ? this.resolvePath(e, false) : e).filter(e => e);
resolvedVariables.push(...entries);
const resolvedVariable: string = util.resolveVariables(entry, env);
if (resolvedVariable.includes("env:")) {
// Do not futher try to resolve a "${env:VAR}"
resolvedVariables.push(resolvedVariable);
} else {
const entries: string[] = resolvedVariable.split(path.delimiter).map(e => glob ? this.resolvePath(e, false) : e).filter(e => e);
resolvedVariables.push(...entries);
}
});
if (!glob) {
return resolvedVariables;
@@ -1314,7 +1320,7 @@ export class CppProperties {
}
if (!this.configurationJson) {
this.resetToDefaultSettings(true); // I don't think there's a case where this will be hit anymore.
this.resetToDefaultSettings(true); // I don't think there's a case where this will be hit anymore.
}
void this.applyDefaultIncludePathsAndFrameworks().catch(logAndReturn.undefined);
@@ -1413,12 +1419,12 @@ export class CppProperties {
// Remove disallowed variable overrides
if (this.configurationJson.env) {
delete this.configurationJson.env['workspaceRoot'];
delete this.configurationJson.env['workspaceFolder'];
delete this.configurationJson.env['workspaceFolderBasename'];
delete this.configurationJson.env['execPath'];
delete this.configurationJson.env['pathSeparator'];
delete this.configurationJson.env['default'];
delete this.configurationJson.env.workspaceRoot;
delete this.configurationJson.env.workspaceFolder;
delete this.configurationJson.env.workspaceFolderBasename;
delete this.configurationJson.env.execPath;
delete this.configurationJson.env.pathSeparator;
delete this.configurationJson.env.default;
}
// Warning: There is a chance that this is incorrect in the event that the c_cpp_properties.json file was created before
@@ -1487,7 +1493,7 @@ export class CppProperties {
return success;
}
public resolvePath(input_path: string | undefined, replaceAsterisks: boolean = true): string {
private resolvePath(input_path: string | undefined, replaceAsterisks: boolean = true): string {
if (!input_path || input_path === "${default}") {
return "";
}
@@ -1511,8 +1517,9 @@ export class CppProperties {
result = result.replace(/\*/g, "");
}
// Make sure all paths result to an absolute path
if (!path.isAbsolute(result) && this.rootUri) {
// Make sure all paths result to an absolute path.
// Do not add the root path to an unresolved env variable.
if (!result.includes("env:") && !path.isAbsolute(result) && this.rootUri) {
result = path.join(this.rootUri.fsPath, result);
}
@@ -1604,7 +1611,7 @@ export class CppProperties {
errors.forcedInclude = this.validatePath(config.forcedInclude, {isDirectory: false, skipRelativePaths: true});
errors.compileCommands = this.validatePath(config.compileCommands, {isDirectory: false});
errors.dotConfig = this.validatePath(config.dotConfig, {isDirectory: false});
errors.databaseFilename = this.validatePath((config.browse ? config.browse.databaseFilename : undefined), {isDirectory: false});
errors.databaseFilename = this.validatePath(config.browse ? config.browse.databaseFilename : undefined, {isDirectory: false});
// Validate intelliSenseMode
if (isWindows) {
@@ -1833,7 +1840,7 @@ export class CppProperties {
// Check for path-related squiggles.
let paths: string[] = [];
let compilerPath: string | undefined;
for (const pathArray of [ (currentConfiguration.browse ? currentConfiguration.browse.path : undefined),
for (const pathArray of [ currentConfiguration.browse ? currentConfiguration.browse.path : undefined,
currentConfiguration.includePath, currentConfiguration.macFrameworkPath ]) {
if (pathArray) {
for (const curPath of pathArray) {
@@ -39,8 +39,6 @@ interface BuildOptions {
export class CppBuildTaskProvider implements TaskProvider {
static CppBuildScriptType: string = 'cppbuild';
constructor() { }
public async provideTasks(): Promise<CppBuildTask[]> {
return this.getTasks(false);
}
@@ -137,10 +135,10 @@ export class CppBuildTaskProvider implements TaskProvider {
!isWindows || !info.path.startsWith("/")
);
const cl_to_add: configs.KnownCompiler | undefined = userCompilerIsCl ? undefined : knownCompilers.find(info =>
((path.basename(info.path) === "cl.exe") && compiler_condition(info)));
(path.basename(info.path) === "cl.exe") && compiler_condition(info));
knownCompilers = knownCompilers.filter(info =>
((info === cl_to_add) || (path.basename(info.path) !== "cl.exe" && compiler_condition(info))));
knownCompilers.map<void>(info => {
(info === cl_to_add) || (path.basename(info.path) !== "cl.exe" && compiler_condition(info)));
knownCompilers.forEach(info => {
knownCompilerPathsSet.add(info.path);
});
}
@@ -181,7 +179,7 @@ export class CppBuildTaskProvider implements TaskProvider {
if (!definition) {
const isWindows: boolean = os.platform() === 'win32';
const taskLabel: string = ((appendSourceToName && !compilerPathBase.startsWith(ext.configPrefix)) ?
ext.configPrefix : "") + compilerPathBase + " " + localize("build_active_file", "build active file");
ext.configPrefix : "") + compilerPathBase + " " + localize("build.active.file", "build active file");
const programName: string = util.defaultExePath();
let args: string[] = isCl ?
['/Zi', '/EHsc', '/nologo', `/Fe${programName}`, '${file}'] :
@@ -215,14 +213,14 @@ export class CppBuildTaskProvider implements TaskProvider {
), isCl ? '$msCompile' : '$gcc');
task.group = TaskGroup.Build;
task.detail = detail ? detail : localize("compiler_details", "compiler:") + " " + resolvedcompilerPath;
task.detail = detail ? detail : localize("compiler.details", "compiler:") + " " + resolvedcompilerPath;
return task;
};
public async getJsonTasks(): Promise<CppBuildTask[]> {
const rawJson: any = await this.getRawTasksJson();
const rawTasksJson: any = (!rawJson.tasks) ? new Array() : rawJson.tasks;
const rawTasksJson: any = !rawJson.tasks ? [] : rawJson.tasks;
const buildTasksJson: CppBuildTask[] = rawTasksJson.map((task: any) => {
if (!task.label || !task.type || task.type !== CppBuildTaskProvider.CppBuildScriptType) {
return null;
@@ -261,7 +259,7 @@ export class CppBuildTaskProvider implements TaskProvider {
public async writeBuildTask(taskLabel: string, workspaceFolder?: WorkspaceFolder, setAsDefault: boolean = false): Promise<void> {
const rawTasksJson: any = await this.getRawTasksJson(workspaceFolder);
if (!rawTasksJson.tasks) {
rawTasksJson.tasks = new Array();
rawTasksJson.tasks = [];
}
// Check if the task exists in the user's task.json.
if (rawTasksJson.tasks.find((task: any) => task.label && task.label === taskLabel)) {
@@ -296,7 +294,7 @@ export class CppBuildTaskProvider implements TaskProvider {
...selectedTask.definition,
problemMatcher: selectedTask.problemMatchers,
group: setAsDefault ? { kind: "build", "isDefault": true } : "build",
detail: localize("task_generated_by_debugger", "Task generated by Debugger.")
detail: localize("task.generated.by.debugger", "Task generated by Debugger.")
};
rawTasksJson.tasks.push(newTask);
}
@@ -374,7 +372,7 @@ class CustomBuildTaskTerminal implements Pseudoterminal {
}
telemetry.logLanguageServerEvent("cppBuildTaskStarted");
// At this point we can start using the terminal.
this.writeEmitter.fire(localize("starting_build", "Starting build...") + this.endOfLine);
this.writeEmitter.fire(localize("starting.build", "Starting build...") + this.endOfLine);
await this.doBuild();
}
@@ -172,7 +172,7 @@ export class CustomConfigurationProviderCollection {
let exists: boolean = false;
const existing: CustomProviderWrapper | undefined = this.providers.get(wrapper.extensionId);
if (existing) {
exists = (existing.version === Version.v0 && wrapper.version === Version.v0);
exists = existing.version === Version.v0 && wrapper.version === Version.v0;
}
if (!exists) {
+131 -80
View File
@@ -5,15 +5,15 @@
'use strict';
import * as fs from 'fs';
import * as StreamZip from 'node-stream-zip';
import * as os from 'os';
import * as path from 'path';
import * as rd from 'readline';
import { Readable } from 'stream';
import * as vscode from 'vscode';
import { Range } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import * as yauzl from 'yauzl';
import { logAndReturn } from '../Utility/Async/returns';
import * as util from '../common';
import { PlatformInformation } from '../platform';
import * as telemetry from '../telemetry';
import { Client, DefaultClient, DoxygenCodeActionCommandArguments, openFileVersions } from './client';
import { ClientCollection } from './clientCollection';
@@ -25,7 +25,7 @@ import { PersistentState } from './persistentState';
import { NodeType, TreeNode } from './referencesModel';
import { CppSettings } from './settings';
import { LanguageStatusUI, getUI } from './ui';
import { makeCpptoolsRange, rangeEquals, shouldChangeFromCToCpp } from './utils';
import { makeCpptoolsRange, rangeEquals, shouldChangeFromCToCpp, showInstallCompilerWalkthrough } from './utils';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -43,57 +43,38 @@ let intervalTimer: NodeJS.Timer;
let codeActionProvider: vscode.Disposable;
export const intelliSenseDisabledError: string = "Do not activate the extension when IntelliSense is disabled.";
type VcpkgDatabase = { [key: string]: string[] }; // Stored as <header file entry> -> [<port name>]
type VcpkgDatabase = Record<string, string[]>; // Stored as <header file entry> -> [<port name>]
let vcpkgDbPromise: Promise<VcpkgDatabase>;
function initVcpkgDatabase(): Promise<VcpkgDatabase> {
return new Promise((resolve) => {
yauzl.open(util.getExtensionFilePath('VCPkgHeadersDatabase.zip'), { lazyEntries: true }, (err?: Error | null, zipfile?: yauzl.ZipFile) => {
// Resolves with an empty database instead of rejecting on failure.
const database: VcpkgDatabase = {};
if (err || !zipfile) {
resolve(database);
return;
}
// Waits until the input file is closed before resolving.
zipfile.on('close', () => {
resolve(database);
});
zipfile.on('entry', entry => {
if (entry.fileName !== 'VCPkgHeadersDatabase.txt') {
zipfile.readEntry();
async function initVcpkgDatabase(): Promise<VcpkgDatabase> {
const database: VcpkgDatabase = {};
try {
const zip = new StreamZip.async({ file: util.getExtensionFilePath('VCPkgHeadersDatabase.zip') });
try {
const data = await zip.entryData('VCPkgHeadersDatabase.txt');
const lines = data.toString().split('\n');
lines.forEach(line => {
const portFilePair: string[] = line.split(':');
if (portFilePair.length !== 2) {
return;
}
zipfile.openReadStream(entry, (err?: Error | null, stream?: Readable) => {
if (err || !stream) {
zipfile.close();
return;
}
const reader: rd.ReadLine = rd.createInterface(stream);
reader.on('line', (lineText: string) => {
const portFilePair: string[] = lineText.split(':');
if (portFilePair.length !== 2) {
return;
}
const portName: string = portFilePair[0];
const relativeHeader: string = portFilePair[1];
const portName: string = portFilePair[0];
const relativeHeader: string = portFilePair[1];
if (!database[relativeHeader]) {
database[relativeHeader] = [];
}
if (!database[relativeHeader]) {
database[relativeHeader] = [];
}
database[relativeHeader].push(portName);
});
reader.on('close', () => {
// We found the one file we wanted.
// It's OK to close instead of progressing through more files in the zip.
zipfile.close();
});
});
database[relativeHeader].push(portName);
});
zipfile.readEntry();
});
});
} catch {
console.log("Unable to parse vcpkg database file.");
}
await zip.close();
} catch {
console.log("Unable to open vcpkg database file.");
}
return database;
}
function getVcpkgHelpAction(): vscode.CodeAction {
@@ -118,7 +99,7 @@ async function lookupIncludeInVcpkg(document: vscode.TextDocument, line: number)
if (!matches || !matches.length || !matches.groups) {
return [];
}
const missingHeader: string = matches.groups['includeFile'].replace(/\//g, '\\');
const missingHeader: string = matches.groups.includeFile.replace(/\//g, '\\');
let portsWithHeader: string[] | undefined;
const vcpkgDb: VcpkgDatabase = await vcpkgDbPromise;
@@ -137,20 +118,20 @@ function isMissingIncludeDiagnostic(diagnostic: vscode.Diagnostic): boolean {
}
function sendActivationTelemetry(): void {
const activateEvent: { [key: string]: string } = {};
const activateEvent: Record<string, string> = {};
// Don't log telemetry for machineId if it's a special value used by the dev host: someValue.machineid
if (vscode.env.machineId !== "someValue.machineId") {
const machineIdPersistentState: PersistentState<string | undefined> = new PersistentState<string | undefined>("CPP.machineId", undefined);
if (!machineIdPersistentState.Value) {
activateEvent["newMachineId"] = vscode.env.machineId;
activateEvent.newMachineId = vscode.env.machineId;
} else if (machineIdPersistentState.Value !== vscode.env.machineId) {
activateEvent["newMachineId"] = vscode.env.machineId;
activateEvent["oldMachineId"] = machineIdPersistentState.Value;
activateEvent.newMachineId = vscode.env.machineId;
activateEvent.oldMachineId = machineIdPersistentState.Value;
}
machineIdPersistentState.Value = vscode.env.machineId;
}
if (vscode.env.uiKind === vscode.UIKind.Web) {
activateEvent["WebUI"] = "1";
activateEvent.WebUI = "1";
}
telemetry.logLanguageServerEvent("Activate", activateEvent);
}
@@ -278,14 +259,14 @@ export function updateLanguageConfigurations(): void {
async function onDidChangeSettings(event: vscode.ConfigurationChangeEvent): Promise<void> {
const client: Client = clients.getDefaultClient();
if (client instanceof DefaultClient) {
const defaultClient: DefaultClient = <DefaultClient>client;
const changedDefaultClientSettings: { [key: string]: string } = await defaultClient.onDidChangeSettings(event);
const defaultClient: DefaultClient = client as DefaultClient;
const changedDefaultClientSettings: Record<string, string> = await defaultClient.onDidChangeSettings(event);
clients.forEach(client => {
if (client !== defaultClient) {
void client.onDidChangeSettings(event).catch(logAndReturn.undefined);
}
});
const newUpdateChannel: string = changedDefaultClientSettings['updateChannel'];
const newUpdateChannel: string = changedDefaultClientSettings.updateChannel;
if (newUpdateChannel || event.affectsConfiguration("extensions.autoUpdate")) {
UpdateInsidersAccess();
}
@@ -407,8 +388,8 @@ export function registerCommands(enabled: boolean): void {
commandDisposables.length = 0;
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SwitchHeaderSource', enabled ? onSwitchHeaderSource : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResetDatabase', enabled ? onResetDatabase : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SelectDefaultCompiler', enabled ? selectDefaultCompiler : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.SelectIntelliSenseConfiguration', enabled ? selectIntelliSenseConfiguration : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.InstallCompiler', enabled ? installCompiler : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationSelect', enabled ? onSelectConfiguration : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationProviderSelect', enabled ? onSelectConfigurationProvider : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ConfigurationEditJSON', enabled ? onEditConfigurationJSON : onDisabledCommand));
@@ -424,7 +405,6 @@ export function registerCommands(enabled: boolean): void {
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.PauseCodeAnalysis', enabled ? onPauseCodeAnalysis : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ResumeCodeAnalysis', enabled ? onResumeCodeAnalysis : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CancelCodeAnalysis', enabled ? onCancelCodeAnalysis : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ShowParsingCommands', enabled ? onShowParsingCommands : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.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));
@@ -457,6 +437,10 @@ export function registerCommands(enabled: boolean): void {
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CreateDeclarationOrDefinition', enabled ? onCreateDeclarationOrDefinition : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.CopyDeclarationOrDefinition', enabled ? onCopyDeclarationOrDefinition : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.RescanCompilers', enabled ? onRescanCompilers : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ExtractToFunction', enabled ? () => onExtractToFunction(false, false) : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ExtractToFreeFunction', enabled ? () => onExtractToFunction(true, false) : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ExtractToMemberFunction', enabled ? () => onExtractToFunction(false, true) : onDisabledCommand));
commandDisposables.push(vscode.commands.registerCommand('C_Cpp.ExpandSelection', enabled ? (r: Range) => onExpandSelection(r) : onDisabledCommand));
}
function onDisabledCommand() {
@@ -498,7 +482,7 @@ async function onSwitchHeaderSource(): Promise<void> {
let targetFileNameReplaced: boolean = false;
clients.forEach(client => {
if (!targetFileNameReplaced && client.RootRealPath && client.RootPath !== client.RootRealPath
&& targetFileName.indexOf(client.RootRealPath) === 0) {
&& targetFileName.startsWith(client.RootRealPath)) {
targetFileName = client.RootPath + targetFileName.substring(client.RootRealPath.length);
targetFileNameReplaced = true;
}
@@ -547,11 +531,6 @@ async function onResetDatabase(): Promise<void> {
clients.ActiveClient.resetDatabase();
}
async function selectDefaultCompiler(sender?: any): Promise<void> {
await clients.ActiveClient.ready;
return clients.ActiveClient.promptSelectCompiler(true, sender);
}
async function onRescanCompilers(sender?: any): Promise<void> {
await clients.ActiveClient.ready;
return clients.ActiveClient.rescanCompilers(sender);
@@ -559,7 +538,64 @@ async function onRescanCompilers(sender?: any): Promise<void> {
async function selectIntelliSenseConfiguration(sender?: any): Promise<void> {
await clients.ActiveClient.ready;
return clients.ActiveClient.promptSelectIntelliSenseConfiguration(true, sender);
return clients.ActiveClient.promptSelectIntelliSenseConfiguration(sender);
}
async function installCompiler(sender?: any): Promise<void> {
const telemetryProperties = { sender: util.getSenderType(sender), platform: os.platform(), ranCommand: 'false' };
const ok = localize('ok', 'OK');
switch (os.platform()) {
case "win32":
showInstallCompilerWalkthrough();
break;
case "darwin": {
const title = localize('install.compiler.mac.title', 'The clang compiler will now be installed');
const detail = localize('install.compiler.mac.detail', 'You may be prompted to type your password in the VS Code terminal window to authorize the installation.');
const response = await vscode.window.showInformationMessage(title, { modal: true, detail }, ok);
if (response === ok) {
const terminal = vscode.window.createTerminal('Install C++ Compiler');
terminal.sendText('sudo xcode-select --install');
terminal.show();
telemetryProperties.ranCommand = 'true';
}
break;
}
default: {
const info = await PlatformInformation.GetPlatformInformation();
const installCommand = (() => {
switch (info.distribution?.name) {
case 'ubuntu':
case 'linuxmint':
case 'debian': {
return 'sudo sh -c \'apt update ; apt install -y build-essential\'';
}
case 'centos':
case 'fedora':
case 'rhel': {
return 'sudo sh -c \'yum install -y gcc-c++ gdb\'';
}
case 'opensuse':
case 'opensuse-leap':
case 'opensuse-tumbleweed': {
return 'sudo sh -c \'zypper refresh ; zypper install gcc-c++ gdb\'';
}
}
return undefined;
})();
if (installCommand) {
const title = localize('install.compiler.linux.title', 'The gcc compiler will now be installed');
const detail = localize('install.compiler.linux.detail', 'You may be prompted to type your password in the VS Code terminal window to authorize the installation.');
const response = await vscode.window.showInformationMessage(title, { modal: true, detail }, ok);
if (response === ok) {
const terminal = vscode.window.createTerminal('Install C++ Compiler');
terminal.sendText(installCommand);
terminal.show(true);
telemetryProperties.ranCommand = 'true';
}
}
}
}
telemetry.logLanguageServerEvent('installCompiler', telemetryProperties);
}
async function onSelectConfiguration(): Promise<void> {
@@ -696,7 +732,7 @@ async function onDisableAllTypeCodeAnalysisProblems(code: string, identifiersAnd
async function onCopyDeclarationOrDefinition(args?: any): Promise<void> {
const sender: any | undefined = util.isString(args?.sender) ? args.sender : args;
const properties: { [key: string]: string } = {
const properties: Record<string, string> = {
sender: util.getSenderType(sender)
};
telemetry.logLanguageServerEvent('CopyDeclDefn', properties);
@@ -705,13 +741,32 @@ async function onCopyDeclarationOrDefinition(args?: any): Promise<void> {
async function onCreateDeclarationOrDefinition(args?: any): Promise<void> {
const sender: any | undefined = util.isString(args?.sender) ? args.sender : args;
const properties: { [key: string]: string } = {
const properties: Record<string, string> = {
sender: util.getSenderType(sender)
};
telemetry.logLanguageServerEvent('CreateDeclDefn', properties);
return getActiveClient().handleCreateDeclarationOrDefinition(false, args?.range);
}
async function onExtractToFunction(extractAsGlobal: boolean, extractAsMemberFunction: boolean): Promise<void> {
if (extractAsGlobal) {
telemetry.logLanguageServerEvent('ExtractToFreeFunction');
} else if (extractAsMemberFunction) {
telemetry.logLanguageServerEvent('ExtractToMemberFunction');
} else {
telemetry.logLanguageServerEvent('ExtractToFunction');
}
return getActiveClient().handleExtractToFunction(extractAsGlobal);
}
function onExpandSelection(r: Range) {
const activeTextEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
if (activeTextEditor) {
activeTextEditor.selection = new vscode.Selection(new vscode.Position(r.start.line, r.start.character), new vscode.Position(r.end.line, r.end.character));
telemetry.logLanguageServerEvent('ExpandSelection');
}
}
function onAddToIncludePath(path: string): void {
if (isFolderOpen()) {
// This only applies to the active client. It would not make sense to add the include path
@@ -764,10 +819,6 @@ function onCancelCodeAnalysis(): void {
clients.ActiveClient.CancelCodeAnalysis();
}
function onShowParsingCommands(): Promise<void> {
return clients.ActiveClient.handleShowParsingCommands();
}
function onShowActiveCodeAnalysisCommands(): Promise<void> {
return clients.ActiveClient.handleShowActiveCodeAnalysisCommands();
}
@@ -838,7 +889,7 @@ async function onVcpkgClipboardInstallSuggested(ports?: string[]): Promise<void>
portsPromises.push(lookupIncludeInVcpkg(docAndLineNumbers[0], line));
});
});
ports = ([] as string[]).concat(...(await Promise.all(portsPromises)));
ports = ([] as string[]).concat(...await Promise.all(portsPromises));
if (!ports.length) {
return;
}
@@ -903,7 +954,7 @@ function reportMacCrashes(): void {
const home: string = os.homedir();
const crashFolder: string = path.resolve(home, "Library/Logs/DiagnosticReports");
fs.stat(crashFolder, (err) => {
const crashObject: { [key: string]: string } = {};
const crashObject: Record<string, string> = {};
if (err?.code) {
// If the directory isn't there, we have a problem...
crashObject["fs.stat: err.code"] = err.code;
@@ -947,12 +998,12 @@ let previousMacCrashData: string;
let previousMacCrashCount: number = 0;
function logMacCrashTelemetry(data: string): void {
const crashObject: { [key: string]: string } = {};
const crashCountObject: { [key: string]: number } = {};
crashObject["CrashingThreadCallStack"] = data;
const crashObject: Record<string, string> = {};
const crashCountObject: Record<string, number> = {};
crashObject.CrashingThreadCallStack = data;
previousMacCrashCount = data === previousMacCrashData ? previousMacCrashCount + 1 : 0;
previousMacCrashData = data;
crashCountObject["CrashCount"] = previousMacCrashCount;
crashCountObject.CrashCount = previousMacCrashCount;
telemetry.logLanguageServerEvent("MacCrash", crashObject, crashCountObject);
}
@@ -1030,8 +1081,8 @@ function handleMacCrashFileRead(err: NodeJS.ErrnoException | undefined | null, d
lines.forEach((line: string) => {
if (!line.includes(".dylib") && !line.includes("???")) {
line = line.replace(/^\d+\s+/, ""); // Remove <numbers><spaces> from the start of the line.
line = line.replace(/std::__1::/g, "std::"); // __1:: is not helpful.
data += (line + "\n");
line = line.replace(/std::__1::/g, "std::"); // __1:: is not helpful.
data += line + "\n";
}
});
data = data.trimRight();
@@ -24,7 +24,7 @@ interface Rules {
end: vscode.OnEnterRule[];
}
const escapeChars: RegExp = /[\\\^\$\*\+\?\{\}\(\)\.\!\=\|\[\]\ \/]/; // characters that should be escaped.
const escapeChars: RegExp = /[\\\^\$\*\+\?\{\}\(\)\.\!\=\|\[\]\ \/]/; // characters that should be escaped.
// Insert '\\' in front of regexp escape chars.
function escape(chars: string): string {
@@ -238,8 +238,8 @@ export function getLanguageConfig(languageId: string): vscode.LanguageConfigurat
}
export function getLanguageConfigFromPatterns(languageId: string, patterns?: (string | CommentPattern)[]): vscode.LanguageConfiguration {
const beginPatterns: string[] = []; // avoid duplicate rules
const continuePatterns: string[] = []; // avoid duplicate rules
const beginPatterns: string[] = []; // avoid duplicate rules
const continuePatterns: string[] = []; // avoid duplicate rules
let duplicates: boolean = false;
let beginRules: vscode.OnEnterRule[] = [];
let continueRules: vscode.OnEnterRule[] = [];
@@ -271,7 +271,7 @@ export function getLanguageConfigFromPatterns(languageId: string, patterns?: (st
if (duplicates) {
getOutputChannel().appendLine(localize("duplicate.multiline.patterns", "Duplicate multiline comment patterns detected."));
}
return { onEnterRules: beginRules.concat(continueRules).concat(endRules).filter(e => (e)) }; // Remove any 'undefined' entries
return { onEnterRules: beginRules.concat(continueRules).concat(endRules).filter(e => e) }; // Remove any 'undefined' entries
}
function constructCommentRules(comment: CommentPattern, languageId: string): Rules {
@@ -24,7 +24,7 @@ export class ReferencesModel {
// Currently, the hierarchy is built each time referencesTreeDataProvider requests nodes.
for (const r of results) {
// Add reference to file
const noReferenceLocation: boolean = (r.position.line === 0 && r.position.character === 0);
const noReferenceLocation: boolean = r.position.line === 0 && r.position.character === 0;
if (noReferenceLocation) {
const node: TreeNode = new TreeNode(this, NodeType.fileWithPendingRef);
node.fileUri = vscode.Uri.file(r.file);
@@ -79,7 +79,7 @@ export class ReferencesModel {
for (const n of filteredFiles) {
const i: number = result.findIndex(item => item.filename === n.filename);
if (i < 0) {
const nodeType: NodeType = (n.node === NodeType.fileWithPendingRef ? NodeType.fileWithPendingRef : NodeType.file);
const nodeType: NodeType = n.node === NodeType.fileWithPendingRef ? NodeType.fileWithPendingRef : NodeType.file;
const node: TreeNode = new TreeNode(this, nodeType);
node.filename = n.filename;
node.fileUri = n.fileUri;
@@ -140,11 +140,11 @@ export class ReferencesModel {
}
export enum NodeType {
undefined, // Use undefined for creating a flat raw list of reference results.
referenceType, // A node to group reference types.
file, // File node that has reference nodes.
fileWithPendingRef, // File node with pending references to find (e.g. it has no reference children yet).
reference // A reference node, which is either a string, comment, inactive reference, etc.
undefined, // Use undefined for creating a flat raw list of reference results.
referenceType, // A node to group reference types.
file, // File node that has reference nodes.
fileWithPendingRef, // File node with pending references to find (e.g. it has no reference children yet).
reference // A reference node, which is either a string, comment, inactive reference, etc.
}
export class TreeNode {
@@ -77,8 +77,8 @@ export class FindAllRefsView {
const fileReferences: TreeNode[] = this.referencesModel.getAllFilesWithPendingReferenceNodes();
for (const fileRef of fileReferences) {
const line: string =
("[" + getReferenceTagString(ReferenceType.ConfirmationInProgress, this.referencesModel.isCanceled) + "] "
+ fileRef.filename);
"[" + getReferenceTagString(ReferenceType.ConfirmationInProgress, this.referencesModel.isCanceled) + "] "
+ fileRef.filename;
fileRefs.push(line);
}
+4 -1
View File
@@ -132,6 +132,7 @@ export interface WorkspaceFolderSettingsParams {
editorAutoClosingBrackets: string | undefined;
editorInlayHintsEnabled: boolean | undefined;
editorParameterHintsEnabled: boolean | undefined;
refactoringIncludeHeader: string | undefined;
}
export interface SettingsParams {
@@ -159,7 +160,7 @@ export interface SettingsParams {
}
function getTarget(): vscode.ConfigurationTarget {
return (vscode.workspace.workspaceFolders) ? vscode.ConfigurationTarget.WorkspaceFolder : vscode.ConfigurationTarget.Global;
return vscode.workspace.workspaceFolders ? vscode.ConfigurationTarget.WorkspaceFolder : vscode.ConfigurationTarget.Global;
}
class Settings {
@@ -368,9 +369,11 @@ export class CppSettings extends Settings {
public get workspaceParsingPriority(): string | undefined { return super.Section.get<string>("workspaceParsingPriority"); }
public get workspaceSymbols(): string | undefined { return super.Section.get<string>("workspaceSymbols"); }
public get exclusionPolicy(): string | undefined { return super.Section.get<string>("exclusionPolicy"); }
public get refactoringIncludeHeader(): string | undefined { return super.Section.get<string>("refactoring.includeHeader"); }
public get simplifyStructuredComments(): boolean | undefined { return super.Section.get<boolean>("simplifyStructuredComments"); }
public get doxygenGeneratedCommentStyle(): string | undefined { return super.Section.get<string>("doxygen.generatedStyle"); }
public get doxygenGenerateOnType(): boolean | undefined { return super.Section.get<boolean>("doxygen.generateOnType"); }
// eslint-disable-next-line no-extra-parens
public get commentContinuationPatterns(): (string | CommentPattern)[] | undefined { return super.Section.get<(string | CommentPattern)[]>("commentContinuationPatterns"); }
public get configurationWarnings(): boolean | undefined { return super.Section.get<string>("configurationWarnings")?.toLowerCase() !== "disabled"; }
public get preferredPathSeparator(): string | undefined { return super.Section.get<string>("preferredPathSeparator"); }
@@ -123,7 +123,7 @@ export class SettingsPanel {
localResourceRoots: [
vscode.Uri.file(util.extensionPath),
vscode.Uri.file(path.join(util.extensionPath, 'ui')),
vscode.Uri.file(path.join(util.extensionPath, 'out', 'ui'))]
vscode.Uri.file(path.join(util.extensionPath, 'dist', 'ui'))]
}
);
@@ -229,7 +229,7 @@ export class SettingsPanel {
private updateWebview(configSelection: string[], configuration: config.Configuration, errors: config.ConfigurationErrors | null): void {
this.configValues = deepCopy(configuration); // Copy configuration values
this.isIntelliSenseModeDefined = (this.configValues.intelliSenseMode !== undefined);
this.isIntelliSenseModeDefined = this.configValues.intelliSenseMode !== undefined;
if (this.panel && this.initialized) {
void this.panel.webview.postMessage({ command: 'setKnownCompilers', compilers: this.compilerPaths });
void this.panel.webview.postMessage({ command: 'updateConfigSelection', selections: configSelection, selectedIndex: this.configIndexSelected });
@@ -389,7 +389,7 @@ export class SettingsPanel {
content = content.replace(
/{{cpp_image_uri}}/g,
cppImageUri.toString());
const settingsJsUri: vscode.Uri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(util.extensionPath, 'out/ui/settings.js')));
const settingsJsUri: vscode.Uri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(util.extensionPath, 'dist/ui/settings.js')));
content = content.replace(
/{{settings_js_uri}}/g,
settingsJsUri.toString());
@@ -49,7 +49,7 @@ export class SettingsTracker {
}
// Iterate through dotted "sub" settings.
const collectSettingsRecursive = (key: string, val: Object, depth: number) => {
const collectSettingsRecursive = (key: string, val: Record<string, any>, depth: number) => {
if (depth > 4) {
// Limit settings recursion to 4 dots (not counting the first one in: `C_Cpp.`)
return;
@@ -69,13 +69,13 @@ export class TimeTelemetryCollector {
const startTime: number = timeStamps.firstFile ? timeStamps.firstFile : timeStamps.didOpen;
let properties: any = {};
let metrics: any = {
"setupTime": (timeStamps.setup - timeStamps.didOpen),
"updateRangeTime": (timeStamps.updateRange - timeStamps.setup),
"totalTime": (timeStamps.updateRange - startTime)
"setupTime": timeStamps.setup - timeStamps.didOpen,
"updateRangeTime": timeStamps.updateRange - timeStamps.setup,
"totalTime": timeStamps.updateRange - startTime
};
if (timeStamps.firstFile) {
properties = { "coldstart": "true" };
metrics = { "activationTime": (timeStamps.didOpen - startTime), ...metrics };
metrics = { "activationTime": timeStamps.didOpen - startTime, ...metrics };
}
telemetry.logLanguageServerEvent("timeStamps", properties, metrics);
+315 -390
View File
@@ -6,7 +6,6 @@
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { sleep } from '../Utility/Async/sleep';
import * as util from '../common';
import * as telemetry from '../telemetry';
import { Client } from './client';
@@ -26,18 +25,6 @@ interface KeyedQuickPickItem extends vscode.QuickPickItem {
key: string;
}
// Higher numbers mean greater priority.
enum ConfigurationPriority {
IncludePath = 1,
CompileCommands = 2,
CustomProvider = 3,
}
interface ConfigurationStatus {
configured: boolean;
priority: ConfigurationPriority;
}
enum LanguageStatusPriority {
First = 0,
High = 1,
@@ -58,264 +45,78 @@ const commandArguments: string[] = []; // We report the sender of the command
export class LanguageStatusUI {
private currentClient: Client | undefined;
private configStatusBarItem: vscode.StatusBarItem;
private browseEngineStatusItem: vscode.LanguageStatusItem;
// Timer for icons from appearing too often and for too short of a time.
private readonly iconDelayTime: number = 1000;
// IntelliSense language status
private intelliSenseStatusItem: vscode.LanguageStatusItem;
private configureIntelliSenseStatusItem: vscode.StatusBarItem;
private referencesStatusBarItem: vscode.StatusBarItem;
private codeAnalysisStatusItem: vscode.LanguageStatusItem;
/** **************************************************** */
private curConfigurationStatus?: Promise<ConfigurationStatus>;
private readonly updatingIntelliSenseText: string = localize("updating.intellisense.text", "IntelliSense: Updating");
private readonly idleIntelliSenseText: string = localize("idle.intellisense.text", "IntelliSense: Ready");
// Tag parse language status
private tagParseStatusItem: vscode.LanguageStatusItem;
private isParsingWorkspace: boolean = false;
private isParsingWorkspacePaused: boolean = false;
private isParsingFiles: boolean = false;
private tagParseTimeout?: NodeJS.Timeout;
private readonly dataBaseIcon: string = "$(database)";
private readonly workspaceParsingInitializing: string = localize("initializing.tagparser.text", "Initializing Workspace");
private readonly workspaceParsingIndexing: string = localize("indexing.tagparser.text", "Indexing Workspace");
private readonly workspaceParsingRunningText: string = localize("running.tagparser.text", "Parsing Workspace");
private readonly workspaceParsingPausedText: string = localize("paused.tagparser.text", "Parsing Workspace: Paused");
private readonly workspaceParsingDoneText: string = localize("complete.tagparser.text", "Parsing Complete");
private readonly workspaceRescanText: string = localize("rescan.tagparse.text", "Rescan Workspace");
private readonly parsingFilesTooltip: string = localize("c.cpp.parsing.open.files.tooltip", "Parsing Open Files");
// Code analysis language status
private codeAnalysisStatusItem: vscode.LanguageStatusItem;
private isRunningCodeAnalysis: boolean = false;
private isCodeAnalysisPaused: boolean = false;
private codeAnalysisProcessed: number = 0;
private codeAnalysisTotal: number = 0;
private readonly workspaceParsingRunningText: string = localize("running.tagparser.text", "Parsing Workspace");
private readonly workspaceParsingPausedText: string = localize("paused.tagparser.text", "Parsing Workspace: Paused");
private readonly workspaceParsingDoneText: string = localize("complete.tagparser.text", "Parsing Complete");
private readonly workspaceParsingInitializing: string = localize("initializing.tagparser.text", "Initializing Workspace");
private readonly workspaceParsingIndexing: string = localize("indexing.tagparser.text", "Indexing Workspace");
private workspaceParsingStatus: string = "";
private workspaceParsingProgress: string = "";
private readonly workspaceRescanText = localize("rescan.tagparse.text", "Rescan Workspace");
private readonly parsingFilesTooltip: string = localize("c.cpp.parsing.open.files.tooltip", "Parsing Open Files");
private readonly referencesPreviewTooltip: string = ` (${localize("click.to.preview", "click to preview results")})`;
private readonly updatingIntelliSenseText: string = localize("updating.intellisense.text", "IntelliSense: Updating");
private readonly idleIntelliSenseText: string = localize("idle.intellisense.text", "IntelliSense: Ready");
private readonly missingIntelliSenseText: string = localize("absent.intellisense.text", "IntelliSense: Not configured");
private codeAnalysProgress: string = "";
private readonly codeAnalysisRunningText: string = localize("running.analysis.text", "Code Analysis: Running");
private readonly codeAnalysisPausedText: string = localize("paused.analysis.text", "Code Analysis: Paused");
private readonly codeAnalysisModePrefix: string = localize("mode.analysis.prefix", "Code Analysis Mode: ");
private codeAnalysProgress: string = "";
// Prevent icons from appearing too often and for too short of a time.
private readonly iconDelayTime: number = 1000;
// References status bar
private referencesStatusBarItem: vscode.StatusBarItem;
private readonly referencesPreviewTooltip: string = ` (${localize("click.to.preview", "click to preview results")})`;
// Configuration status bar
private configurationStatusBarItem: vscode.StatusBarItem;
// Configure IntelliSense status bar
private configureIntelliSenseStatusBarItem: vscode.StatusBarItem;
private showConfigureIntelliSenseButton: boolean = false;
private configureIntelliSenseTimeout?: NodeJS.Timeout;
private readonly configureIntelliSenseText: string = localize("c.cpp.configureIntelliSenseStatus.text", "Configure IntelliSense");
private readonly cppConfigureIntelliSenseText: string = localize("c.cpp.configureIntelliSenseStatus.cppText", "C/C++ Configure IntelliSense");
constructor() {
const configTooltip: string = localize("c.cpp.configuration.tooltip", "C/C++ Configuration");
this.configStatusBarItem = vscode.window.createStatusBarItem("c.cpp.configuration.tooltip", vscode.StatusBarAlignment.Right, 0);
this.configStatusBarItem.name = configTooltip;
this.configStatusBarItem.command = {
command: "C_Cpp.ConfigurationSelect",
title: configTooltip,
arguments: commandArguments
};
this.configStatusBarItem.tooltip = configTooltip;
this.ShowConfiguration = true;
this.intelliSenseStatusItem = this.createIntelliSenseStatusItem();
this.tagParseStatusItem = this.createTagParseStatusItem();
this.codeAnalysisStatusItem = this.createCodeAnalysisStatusItem();
this.referencesStatusBarItem = vscode.window.createStatusBarItem(`c.cpp.references.statusbar`, vscode.StatusBarAlignment.Right, 901);
this.referencesStatusBarItem.name = localize("c.cpp.references.statusbar", "C/C++ References Status");
this.referencesStatusBarItem.tooltip = "";
this.referencesStatusBarItem.command = {
command: "C_Cpp.ShowReferencesProgress",
title: this.referencesStatusBarItem.name,
arguments: commandArguments
};
this.referencesStatusBarItem = this.createReferencesStatusBarItem();
this.ShowReferencesIcon = false;
this.configureIntelliSenseStatusItem = vscode.window.createStatusBarItem(`c.cpp.configureIntelliSenseStatus.statusbar`, vscode.StatusBarAlignment.Right, 0);
this.configureIntelliSenseStatusItem.name = this.cppConfigureIntelliSenseText;
this.configureIntelliSenseStatusItem.tooltip = this.cppConfigureIntelliSenseText;
this.configureIntelliSenseStatusItem.text = `$(warning) ${this.configureIntelliSenseText}`;
this.configureIntelliSenseStatusItem.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
this.configureIntelliSenseStatusItem.command = {
command: "C_Cpp.SelectIntelliSenseConfiguration",
title: this.configureIntelliSenseStatusItem.name,
arguments: ['statusBar']
};
this.configurationStatusBarItem = this.createConfigurationStatusBarItem();
this.ShowConfiguration = true;
this.configureIntelliSenseStatusBarItem = this.createConfigureIntelliSenseStatusBarItem();
void this.ShowConfigureIntelliSenseButton(false, this.currentClient);
this.intelliSenseStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.intellisense`, util.documentSelector);
this.intelliSenseStatusItem.name = localize("cpptools.status.intellisense", "C/C++ IntelliSense Status");
this.intelliSenseStatusItem.text = this.idleIntelliSenseText;
this.browseEngineStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.tagparser`, util.documentSelector);
this.browseEngineStatusItem.name = localize("cpptools.status.tagparser", "C/C++ Tag Parser Status");
this.browseEngineStatusItem.detail = localize("cpptools.detail.tagparser", "Initializing...");
this.browseEngineStatusItem.text = "$(database)";
this.browseEngineStatusItem.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments
};
this.workspaceParsingStatus = this.workspaceParsingRunningText;
this.codeAnalysisStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Low}.codeanalysis`, util.documentSelector);
this.codeAnalysisStatusItem.name = localize("cpptools.status.codeanalysis", "C/C++ Code Analysis Status");
this.codeAnalysisStatusItem.text = this.codeAnalysisModePrefix + this.codeAnalysisCurrentMode();
this.codeAnalysisStatusItem.command = {
command: "C_Cpp.ShowIdleCodeAnalysisCommands",
title: localize("c.cpp.codeanalysis.statusbar.runNow", "Run Now"),
arguments: commandArguments
};
}
private set TagParseStatus(label: string) {
this.workspaceParsingProgress = label;
if (this.browseEngineStatusItem.command) {
// Currently needed in order to update hover tooltip
this.browseEngineStatusItem.command.tooltip = (this.isParsingFiles ? `${this.parsingFilesTooltip} | ` : "") + this.workspaceParsingProgress;
}
}
private setIsInitializingWorkspace(val: boolean): void {
if (val) {
this.browseEngineStatusItem.text = "$(database)";
this.browseEngineStatusItem.detail = this.workspaceParsingInitializing;
}
}
private setIsIndexingWorkspace(val: boolean): void {
if (val) {
this.browseEngineStatusItem.text = "$(database)";
this.browseEngineStatusItem.detail = this.workspaceParsingIndexing;
this.browseEngineStatusItem.busy = true;
}
}
private set ActiveConfig(label: string) {
this.configStatusBarItem.text = label;
}
private dbTimeout?: NodeJS.Timeout;
private setIsParsingWorkspace(val: boolean): void {
if (!val && this.isParsingWorkspacePaused) {
// Unpause before handling the no longer parsing state.
this.setIsParsingWorkspacePaused(false);
}
this.isParsingWorkspace = val;
const showIcon: boolean = val || this.isParsingFiles;
// Leave this outside for more real-time response
this.browseEngineStatusItem.busy = showIcon;
if (showIcon) {
this.browseEngineStatusItem.text = "$(database)";
this.browseEngineStatusItem.detail = this.tagParseText();
if (this.dbTimeout) {
clearTimeout(this.dbTimeout);
this.dbTimeout = undefined;
}
} else {
this.dbTimeout = setTimeout(() => {
this.browseEngineStatusItem.text = this.workspaceParsingDoneText;
this.browseEngineStatusItem.detail = "";
this.browseEngineStatusItem.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments
};
}, this.iconDelayTime);
}
}
private tagParseText(): string {
if (this.isParsingWorkspacePaused) {
const twoStatus: boolean = this.isParsingFiles && this.isParsingWorkspace;
return (this.isParsingFiles ? this.parsingFilesTooltip : "")
+ (twoStatus ? " | " : "")
+ (this.isParsingWorkspace ? this.workspaceParsingStatus : "");
} else {
return this.isParsingWorkspace ? this.workspaceParsingStatus : this.parsingFilesTooltip;
}
}
private setIsParsingWorkspacePausable(val: boolean): void {
if (val && this.isParsingWorkspace) {
this.browseEngineStatusItem.command = {
command: "C_Cpp.PauseParsing",
title: localize("tagparser.pause.text", "Pause"),
arguments: commandArguments
};
}
}
private setIsParsingWorkspacePaused(val: boolean): void {
if (!this.isParsingFiles && !this.isParsingWorkspace) {
// Ignore a pause change if no parsing is actually happening.
return;
}
this.isParsingWorkspacePaused = val;
this.browseEngineStatusItem.busy = !val || this.isParsingFiles;
this.browseEngineStatusItem.text = "$(database)";
this.workspaceParsingStatus = val ? this.workspaceParsingPausedText : this.workspaceParsingRunningText;
this.browseEngineStatusItem.detail = this.tagParseText();
this.browseEngineStatusItem.command = val ? {
command: "C_Cpp.ResumeParsing",
title: localize("tagparser.resume.text", "Resume"),
arguments: commandArguments
} : {
command: "C_Cpp.PauseParsing",
title: localize("tagparser.pause.text", "Pause"),
arguments: commandArguments
};
}
private set ShowConfiguration(show: boolean) {
if (show) {
this.configStatusBarItem.show();
} else {
this.configStatusBarItem.hide();
}
}
private setIsCodeAnalysisPaused(val: boolean): void {
if (!this.isRunningCodeAnalysis) {
return;
}
this.isCodeAnalysisPaused = val;
this.codeAnalysisStatusItem.busy = !val;
this.codeAnalysisStatusItem.text = val ? this.codeAnalysisPausedText : this.codeAnalysisRunningText;
}
private setIsParsingFiles(val: boolean): void {
this.isParsingFiles = val;
const showIcon: boolean = val || this.isParsingWorkspace;
// Leave this outside for more real-time response
this.browseEngineStatusItem.busy = val || (!this.isParsingWorkspacePaused && this.isParsingWorkspace);
if (showIcon) {
this.browseEngineStatusItem.text = "$(database)";
this.browseEngineStatusItem.detail = this.tagParseText();
if (this.dbTimeout) {
clearTimeout(this.dbTimeout);
this.dbTimeout = undefined;
}
} else {
this.dbTimeout = setTimeout(() => {
this.browseEngineStatusItem.text = this.workspaceParsingDoneText;
this.browseEngineStatusItem.detail = "";
this.browseEngineStatusItem.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments
};
}, this.iconDelayTime);
}
//#region IntelliSense language status
private createIntelliSenseStatusItem(): vscode.LanguageStatusItem {
const item: vscode.LanguageStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.High}.intellisense`, util.documentSelector);
item.name = localize("cpptools.status.intellisense", "C/C++ IntelliSense Status");
item.text = this.idleIntelliSenseText;
return item;
}
private flameTimeout?: NodeJS.Timeout;
private setIsUpdatingIntelliSense(val: boolean): void {
const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined);
if (settings.intelliSenseEngine === "disabled") {
this.intelliSenseStatusItem.text = this.missingIntelliSenseText;
this.intelliSenseStatusItem.command = {
command: "C_Cpp.SelectDefaultCompiler",
title: localize("intellisense.select.text", "Select a Compiler"),
arguments: commandArguments
};
return;
}
this.intelliSenseStatusItem.busy = val;
if (this.flameTimeout) {
@@ -341,6 +142,149 @@ export class LanguageStatusUI {
arguments: commandArguments
};
}
//#endregion End - IntelliSense language status
//#region Tag parse language status
private createTagParseStatusItem(): vscode.LanguageStatusItem {
const item: vscode.LanguageStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Mid}.tagparser`, util.documentSelector);
item.name = localize("cpptools.status.tagparser", "C/C++ Tag Parser Status");
item.detail = localize("cpptools.detail.tagparser", "Initializing...");
item.text = this.dataBaseIcon;
item.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments
};
return item;
}
private set TagParseStatus(label: string) {
if ((this.isParsingWorkspace || this.isParsingFiles) && this.tagParseStatusItem.command) {
// Create a new command object to force update on tooltip
const updatedCommand: vscode.Command = this.tagParseStatusItem.command;
updatedCommand.tooltip = (this.isParsingFiles ? `${this.parsingFilesTooltip} | ` : "") + label;
this.tagParseStatusItem.command = updatedCommand;
}
}
private setIsInitializingWorkspace(val: boolean): void {
if (val) {
this.tagParseStatusItem.text = this.dataBaseIcon;
this.tagParseStatusItem.detail = this.workspaceParsingInitializing;
}
}
private setIsIndexingWorkspace(val: boolean): void {
if (val) {
this.tagParseStatusItem.text = this.dataBaseIcon;
this.tagParseStatusItem.detail = this.workspaceParsingIndexing;
this.tagParseStatusItem.busy = true;
}
}
private setIsParsingWorkspace(val: boolean): void {
this.isParsingWorkspace = val;
if (!val && this.isParsingWorkspacePaused) {
// Unpause before handling the no longer parsing state.
this.isParsingWorkspacePaused = false;
}
this.setTagParseStatus();
}
private setIsParsingFiles(val: boolean): void {
this.isParsingFiles = val;
this.setTagParseStatus();
}
private setIsParsingWorkspacePaused(val: boolean): void {
this.isParsingWorkspacePaused = val;
if (this.isParsingWorkspace || this.isParsingFiles) {
this.setTagParseStatus();
}
}
private getTagParsingDetail(): string {
if (!this.isParsingWorkspace && !this.isParsingFiles) {
return "";
}
if (this.isParsingWorkspacePaused) {
const displayTwoStatus: boolean = this.isParsingFiles && this.isParsingWorkspace;
return (this.isParsingFiles ? this.parsingFilesTooltip : "")
+ (displayTwoStatus ? " | " : "")
+ (this.isParsingWorkspace ? this.workspaceParsingPausedText : "");
} else {
return this.isParsingWorkspace ? this.workspaceParsingRunningText : this.parsingFilesTooltip;
}
}
private setTagParseStatus(): void {
// Set busy icon outside of timer for more real-time response
this.tagParseStatusItem.busy = (this.isParsingWorkspace && !this.isParsingWorkspacePaused) || this.isParsingFiles;
if (this.tagParseStatusItem.busy && this.tagParseTimeout) {
clearTimeout(this.tagParseTimeout);
this.tagParseTimeout = undefined;
}
if (this.isParsingWorkspace || this.isParsingFiles) {
this.tagParseStatusItem.text = this.dataBaseIcon;
this.tagParseStatusItem.detail = this.getTagParsingDetail();
if (this.isParsingWorkspace) {
// Pausing/resuming is only applicable to parsing workspace.
this.tagParseStatusItem.command = this.isParsingWorkspacePaused ? {
command: "C_Cpp.ResumeParsing",
title: localize("tagparser.resume.text", "Resume"),
arguments: commandArguments,
tooltip: this.tagParseStatusItem.command?.tooltip ?? undefined
} : {
command: "C_Cpp.PauseParsing",
title: localize("tagparser.pause.text", "Pause"),
arguments: commandArguments,
tooltip: this.tagParseStatusItem.command?.tooltip ?? undefined
};
} else {
this.tagParseStatusItem.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments,
tooltip: this.tagParseStatusItem.command?.tooltip ?? undefined
};
}
} else {
// Parsing completed.
this.tagParseTimeout = setTimeout(() => {
this.tagParseStatusItem.text = this.workspaceParsingDoneText;
this.tagParseStatusItem.detail = "";
this.tagParseStatusItem.command = {
command: "C_Cpp.RescanWorkspace",
title: this.workspaceRescanText,
arguments: commandArguments
};
}, this.iconDelayTime);
}
}
//#endregion Tag parse language status
//#region Code analysis language status
private createCodeAnalysisStatusItem(): vscode.LanguageStatusItem {
const item: vscode.LanguageStatusItem = vscode.languages.createLanguageStatusItem(`cpptools.status.${LanguageStatusPriority.Low}.codeanalysis`, util.documentSelector);
item.name = localize("cpptools.status.codeanalysis", "C/C++ Code Analysis Status");
item.text = this.codeAnalysisModePrefix + this.codeAnalysisCurrentMode();
item.command = {
command: "C_Cpp.ShowIdleCodeAnalysisCommands",
title: localize("c.cpp.codeanalysis.statusbar.runNow", "Run Now"),
arguments: commandArguments
};
return item;
}
private setIsCodeAnalysisPaused(val: boolean): void {
if (!this.isRunningCodeAnalysis) {
return;
}
this.isCodeAnalysisPaused = val;
this.codeAnalysisStatusItem.busy = !val;
this.codeAnalysisStatusItem.text = val ? this.codeAnalysisPausedText : this.codeAnalysisRunningText;
}
private codeAnalysisCurrentMode(): string {
const settings: CppSettings = new CppSettings((vscode.workspace.workspaceFolders && vscode.workspace.workspaceFolders.length > 0) ? vscode.workspace.workspaceFolders[0]?.uri : undefined);
@@ -404,11 +348,54 @@ export class LanguageStatusUI {
this.updateCodeAnalysisTooltip();
}
public async showActiveCodeAnalysisCommands(): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = localize("select.code.analysis.command", "Select a code analysis command...");
const items: IndexableQuickPickItem[] = [];
items.push({ label: localize("cancel.analysis", "Cancel"), description: "", index: 0 });
if (this.isCodeAnalysisPaused) {
items.push({ label: localize("resume.analysis", "Resume"), description: "", index: 2 });
} else {
items.push({ label: localize("pause.analysis", "Pause"), description: "", index: 1 });
}
items.push({ label: localize("another.analysis", "Start Another..."), description: "", index: 3 });
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return selection ? selection.index : -1;
}
public async showIdleCodeAnalysisCommands(): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = localize("select.command", "Select a command...");
const items: IndexableQuickPickItem[] = [];
items.push({ label: localize("active.analysis", "Run Code Analysis on Active File"), description: "", index: 0 });
items.push({ label: localize("all.analysis", "Run Code Analysis on All Files"), description: "", index: 1 });
items.push({ label: localize("open.analysis", "Run Code Analysis on Open Files"), description: "", index: 2 });
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return selection ? selection.index : -1;
}
//#endregion Code analysis language status
//#region References status
private createReferencesStatusBarItem(): vscode.StatusBarItem {
const item: vscode.StatusBarItem = vscode.window.createStatusBarItem(`c.cpp.references.statusbar`, vscode.StatusBarAlignment.Right, 901);
item.name = localize("c.cpp.references.statusbar", "C/C++ References Status");
item.tooltip = "";
item.command = {
command: "C_Cpp.ShowReferencesProgress",
title: item.name,
arguments: commandArguments
};
return item;
}
private get ReferencesCommand(): ReferencesCommandMode {
return this.referencesStatusBarItem.tooltip === "" ? ReferencesCommandMode.None :
(this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Find) ? ReferencesCommandMode.Find :
(this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Rename) ? ReferencesCommandMode.Rename :
ReferencesCommandMode.Peek));
this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Find) ? ReferencesCommandMode.Find :
this.referencesStatusBarItem.tooltip === referencesCommandModeToString(ReferencesCommandMode.Rename) ? ReferencesCommandMode.Rename :
ReferencesCommandMode.Peek;
}
private set ReferencesCommand(val: ReferencesCommandMode) {
@@ -429,9 +416,50 @@ export class LanguageStatusUI {
this.referencesStatusBarItem.hide();
}
}
//#endregion End - References status
private showConfigureIntelliSenseButton: boolean = false;
private configureIntelliSenseTimeout?: NodeJS.Timeout;
//#region Configuration status bar
private createConfigurationStatusBarItem(): vscode.StatusBarItem {
const configTooltip: string = localize("c.cpp.configuration.tooltip", "C/C++ Configuration");
const item: vscode.StatusBarItem = vscode.window.createStatusBarItem("c.cpp.configuration.tooltip", vscode.StatusBarAlignment.Right, 0);
item.name = configTooltip;
item.tooltip = configTooltip;
item.command = {
command: "C_Cpp.ConfigurationSelect",
title: configTooltip,
arguments: commandArguments
};
return item;
}
private set ActiveConfig(label: string) {
this.configurationStatusBarItem.text = label;
}
private set ShowConfiguration(show: boolean) {
if (show) {
this.configurationStatusBarItem.show();
} else {
this.configurationStatusBarItem.hide();
}
}
//#endregion End - Configuration status bar
//#region Configure IntelliSense status bar
private createConfigureIntelliSenseStatusBarItem(): vscode.StatusBarItem {
const cppConfigureIntelliSenseText: string = localize("c.cpp.configureIntelliSenseStatus.cppText", "C/C++ Configure IntelliSense");
const item: vscode.StatusBarItem = vscode.window.createStatusBarItem(`c.cpp.configureIntelliSenseStatus.statusbar`, vscode.StatusBarAlignment.Right, 0);
item.name = cppConfigureIntelliSenseText;
item.tooltip = cppConfigureIntelliSenseText;
item.text = `$(warning) ${this.configureIntelliSenseText}`;
item.backgroundColor = new vscode.ThemeColor('statusBarItem.warningBackground');
item.command = {
command: "C_Cpp.SelectIntelliSenseConfiguration",
title: cppConfigureIntelliSenseText,
arguments: ['statusBar']
};
return item;
}
public async ShowConfigureIntelliSenseButton(show: boolean, client?: Client, configurationType?: ConfigurationType, sender?: string): Promise<void> {
if (client !== this.currentClient) {
@@ -442,9 +470,6 @@ export class LanguageStatusUI {
telemetry.logLanguageServerEvent('showConfigureIntelliSenseButton', { configurationType, sender, showButton });
}
if (!await telemetry.showStatusBarIntelliSenseButton()) {
return;
}
this.showConfigureIntelliSenseButton = show;
if (client !== undefined) {
client.setShowConfigureIntelliSenseButton(show);
@@ -453,18 +478,18 @@ export class LanguageStatusUI {
const activeEditor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
telemetry.logLanguageServerEvent('configureIntelliSenseStatusBar');
if (activeEditor && util.isCppOrRelated(activeEditor.document)) {
this.configureIntelliSenseStatusItem.show();
this.configureIntelliSenseStatusBarItem.show();
if (!this.configureIntelliSenseTimeout) {
this.configureIntelliSenseTimeout = setTimeout(() => {
this.configureIntelliSenseStatusItem.text = "$(warning)";
this.configureIntelliSenseStatusBarItem.text = "$(warning)";
}, 15000);
}
}
} else {
this.configureIntelliSenseStatusItem.hide();
this.configureIntelliSenseStatusBarItem.hide();
if (this.configureIntelliSenseTimeout) {
clearTimeout(this.configureIntelliSenseTimeout);
this.configureIntelliSenseStatusItem.text = `$(warning) ${this.configureIntelliSenseText}`;
this.configureIntelliSenseStatusBarItem.text = `$(warning) ${this.configureIntelliSenseText}`;
this.configureIntelliSenseTimeout = undefined;
}
}
@@ -475,7 +500,7 @@ export class LanguageStatusUI {
if (!activeEditor) {
this.ShowConfiguration = false;
if (this.showConfigureIntelliSenseButton) {
this.configureIntelliSenseStatusItem.hide();
this.configureIntelliSenseStatusBarItem.hide();
}
} else {
const isCppPropertiesJson: boolean = util.isCppPropertiesJson(activeEditor.document);
@@ -488,43 +513,23 @@ export class LanguageStatusUI {
// TODO: Check some "AlwaysShow" setting here.
this.ShowConfiguration = isCppOrRelated || (util.getWorkspaceIsCpp() &&
(activeEditor.document.fileName.endsWith("tasks.json") ||
activeEditor.document.fileName.endsWith("launch.json")));
activeEditor.document.fileName.endsWith("launch.json")));
if (this.showConfigureIntelliSenseButton) {
if (isCppOrRelated && !!this.currentClient && this.currentClient.getShowConfigureIntelliSenseButton()) {
this.configureIntelliSenseStatusItem.show();
this.configureIntelliSenseStatusBarItem.show();
if (!this.configureIntelliSenseTimeout) {
this.configureIntelliSenseTimeout = setTimeout(() => {
this.configureIntelliSenseStatusItem.text = "$(warning)";
this.configureIntelliSenseStatusBarItem.text = "$(warning)";
}, 15000);
}
} else {
this.configureIntelliSenseStatusItem.hide();
this.configureIntelliSenseStatusBarItem.hide();
}
}
}
}
public bind(client: Client): void {
client.InitializingWorkspaceChanged(value => { this.setIsInitializingWorkspace(value); });
client.IndexingWorkspaceChanged(value => { this.setIsIndexingWorkspace(value); });
client.ParsingWorkspaceChanged(value => { this.setIsParsingWorkspace(value); });
client.ParsingWorkspacePausableChanged(value => { this.setIsParsingWorkspacePausable(value); });
client.ParsingWorkspacePausedChanged(value => { this.setIsParsingWorkspacePaused(value); });
client.ParsingFilesChanged(value => { this.setIsParsingFiles(value); });
client.IntelliSenseParsingChanged(value => { this.setIsUpdatingIntelliSense(value); });
client.RunningCodeAnalysisChanged(value => { this.setIsRunningCodeAnalysis(value); });
client.CodeAnalysisPausedChanged(value => { this.setIsCodeAnalysisPaused(value); });
client.CodeAnalysisProcessedChanged(value => { this.setCodeAnalysisProcessed(value); });
client.CodeAnalysisTotalChanged(value => { this.setCodeAnalysisTotal(value); });
client.ReferencesCommandModeChanged(value => { this.ReferencesCommand = value; });
client.TagParserStatusChanged(value => { this.TagParseStatus = value; });
client.ActiveConfigChanged(value => {
this.ActiveConfig = value;
this.currentClient = client;
void this.ShowConfigureIntelliSenseButton(client.getShowConfigureIntelliSenseButton(), client);
});
}
//#endregion End - Configure IntelliSense status bar
public async showConfigurations(configurationNames: string[]): Promise<number> {
const options: vscode.QuickPickOptions = {};
@@ -538,7 +543,7 @@ export class LanguageStatusUI {
items.push({ label: localize("edit.configuration.json", "Edit Configurations (JSON)"), description: "", index: configurationNames.length + 1 });
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.index : -1;
return selection ? selection.index : -1;
}
public async showConfigurationProviders(currentProvider?: string): Promise<string | undefined> {
@@ -557,20 +562,7 @@ export class LanguageStatusUI {
items.push({ label: `(${localize("none", "none")})`, description: localize("disable.configuration.provider", "Disable the active configuration provider, if applicable."), key: "" });
const selection: KeyedQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.key : undefined;
}
public async showCompileCommands(paths: string[]): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = localize("select.compile.commands", "Select a compile_commands.json...");
const items: IndexableQuickPickItem[] = [];
for (let i: number = 0; i < paths.length; i++) {
items.push({ label: paths[i], description: "", index: i });
}
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.index : -1;
return selection ? selection.key : undefined;
}
public async showWorkspaces(workspaceNames: { name: string; key: string }[]): Promise<string> {
@@ -581,103 +573,36 @@ export class LanguageStatusUI {
workspaceNames.forEach(name => items.push({ label: name.name, description: "", key: name.key }));
const selection: KeyedQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.key : "";
return selection ? selection.key : "";
}
private readonly selectACommandString: string = localize("select.command", "Select a command...");
private readonly selectACodeAnalysisCommandString: string = localize("select.code.analysis.command", "Select a code analysis command...");
public async showParsingCommands(): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = this.selectACommandString;
const items: IndexableQuickPickItem[] = [];
if (this.isParsingWorkspacePaused) {
items.push({ label: localize("resume.parsing", "Resume Workspace Parsing"), description: "", index: 1 });
} else {
items.push({ label: localize("pause.parsing", "Pause Workspace Parsing"), description: "", index: 0 });
}
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.index : -1;
}
public async showActiveCodeAnalysisCommands(): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = this.selectACodeAnalysisCommandString;
const items: IndexableQuickPickItem[] = [];
items.push({ label: localize("cancel.analysis", "Cancel"), description: "", index: 0 });
if (this.isCodeAnalysisPaused) {
items.push({ label: localize("resume.analysis", "Resume"), description: "", index: 2 });
} else {
items.push({ label: localize("pause.analysis", "Pause"), description: "", index: 1 });
}
items.push({ label: localize("another.analysis", "Start Another..."), description: "", index: 3 });
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.index : -1;
}
public async showIdleCodeAnalysisCommands(): Promise<number> {
const options: vscode.QuickPickOptions = {};
options.placeHolder = this.selectACommandString;
const items: IndexableQuickPickItem[] = [];
items.push({ label: localize("active.analysis", "Run Code Analysis on Active File"), description: "", index: 0 });
items.push({ label: localize("all.analysis", "Run Code Analysis on All Files"), description: "", index: 1 });
items.push({ label: localize("open.analysis", "Run Code Analysis on Open Files"), description: "", index: 2 });
const selection: IndexableQuickPickItem | undefined = await vscode.window.showQuickPick(items, options);
return (selection) ? selection.index : -1;
}
public async showConfigureIncludePathMessage(prompt: () => Promise<boolean>, onSkip: () => void): Promise<void> {
await sleep(10000);
this.showConfigurationPrompt(ConfigurationPriority.IncludePath, prompt, onSkip);
}
public showConfigureCompileCommandsMessage(prompt: () => Promise<boolean>, onSkip: () => void): void {
setTimeout(() => {
this.showConfigurationPrompt(ConfigurationPriority.CompileCommands, prompt, onSkip);
}, 5000);
}
public showConfigureCustomProviderMessage(prompt: () => Promise<boolean>, onSkip: () => void): void {
this.showConfigurationPrompt(ConfigurationPriority.CustomProvider, prompt, onSkip);
}
private showConfigurationPrompt(priority: ConfigurationPriority, prompt: () => Thenable<boolean>, onSkip: () => void): void {
const showPrompt: () => Promise<ConfigurationStatus> = async () => {
const configured: boolean = await prompt();
return Promise.resolve({
priority: priority,
configured: configured
});
};
if (this.curConfigurationStatus) {
this.curConfigurationStatus = this.curConfigurationStatus.then(result => {
if (priority > result.priority) {
return showPrompt();
} else if (!result.configured) {
return showPrompt();
}
onSkip();
return Promise.resolve({
priority: result.priority,
configured: true
});
});
} else {
this.curConfigurationStatus = showPrompt();
}
public bind(client: Client): void {
client.InitializingWorkspaceChanged(value => { this.setIsInitializingWorkspace(value); });
client.IndexingWorkspaceChanged(value => { this.setIsIndexingWorkspace(value); });
client.ParsingWorkspaceChanged(value => { this.setIsParsingWorkspace(value); });
client.ParsingWorkspacePausedChanged(value => { this.setIsParsingWorkspacePaused(value); });
client.ParsingFilesChanged(value => { this.setIsParsingFiles(value); });
client.IntelliSenseParsingChanged(value => { this.setIsUpdatingIntelliSense(value); });
client.RunningCodeAnalysisChanged(value => { this.setIsRunningCodeAnalysis(value); });
client.CodeAnalysisPausedChanged(value => { this.setIsCodeAnalysisPaused(value); });
client.CodeAnalysisProcessedChanged(value => { this.setCodeAnalysisProcessed(value); });
client.CodeAnalysisTotalChanged(value => { this.setCodeAnalysisTotal(value); });
client.ReferencesCommandModeChanged(value => { this.ReferencesCommand = value; });
client.TagParserStatusChanged(value => { this.TagParseStatus = value; });
client.ActiveConfigChanged(value => {
this.ActiveConfig = value;
this.currentClient = client;
void this.ShowConfigureIntelliSenseButton(client.getShowConfigureIntelliSenseButton(), client);
});
}
public dispose(): void {
this.configStatusBarItem.dispose();
this.browseEngineStatusItem.dispose();
this.intelliSenseStatusItem.dispose();
this.referencesStatusBarItem.dispose();
this.tagParseStatusItem.dispose();
this.codeAnalysisStatusItem.dispose();
this.referencesStatusBarItem.dispose();
this.configurationStatusBarItem.dispose();
this.configureIntelliSenseStatusBarItem.dispose();
}
}
+48 -1
View File
@@ -3,8 +3,10 @@
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
'use strict';
import * as os from 'os';
import * as vscode from 'vscode';
import { Range } from 'vscode-languageclient';
import { SessionState } from '../sessionState';
import { Location, TextEdit } from './commonTypes';
import { CppSettings } from './settings';
@@ -34,7 +36,7 @@ export function rangeEquals(range1: vscode.Range | Range, range2: vscode.Range |
// Check this before attempting to switch a document from C to C++.
export function shouldChangeFromCToCpp(document: vscode.TextDocument): boolean {
if ((document.fileName.endsWith(".C") || document.fileName.endsWith(".H"))) {
if (document.fileName.endsWith(".C") || document.fileName.endsWith(".H")) {
const cppSettings: CppSettings = new CppSettings();
if (cppSettings.autoAddFileAssociations) {
return !docsChangedFromCppToC.has(document.fileName);
@@ -51,4 +53,49 @@ export function handleChangedFromCppToC(document: vscode.TextDocument): void {
}
}
export function showInstallCompilerWalkthrough(): void {
// Because we need to conditionally enable/disable steps to alter their contents,
// we need to determine which step is actually visible. If the steps change, this
// logic will need to change to reflect them.
enum Step {
Activation = 'awaiting.activation',
NoCompilers = 'no.compilers.found',
Verify = 'verify.compiler'
}
const step = (() => {
if (!SessionState.scanForCompilersDone.get()) {
return Step.Activation;
} else if (!SessionState.trustedCompilerFound.get()) {
return Step.NoCompilers;
} else {
return Step.Verify;
}
})();
const platform = (() => {
switch (os.platform()) {
case 'win32': return 'windows';
case 'darwin': return 'mac';
default: return 'linux';
}
})();
const version = (platform === 'windows') ? SessionState.windowsVersion.get() : '';
const index = `ms-vscode.cpptools#${step}.${platform}${version}`;
void vscode.commands.executeCommand(
'workbench.action.openWalkthrough',
{ category: 'ms-vscode.cpptools#cppWelcome', step: index },
false)
// Run it twice for now because of VS Code bug #187958
.then(() => vscode.commands.executeCommand(
"workbench.action.openWalkthrough",
{ category: 'ms-vscode.cpptools#cppWelcome', step: index },
false)
);
return;
}
const docsChangedFromCppToC: Set<string> = new Set<string>();
-3
View File
@@ -46,8 +46,6 @@ export interface IInteractor {
export class MitmInteractor implements IInteractor {
static ID = 'mitm';
constructor() { }
get id(): string {
return MitmInteractor.ID;
}
@@ -322,7 +320,6 @@ export class ContinueOnInteractor implements IInteractor {
return ContinueOnInteractor.ID;
}
// eslint-disable-next-line @typescript-eslint/no-unused-vars
async onData(data: string, _cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pattern: string = escapeStringForRegex(this.continueOn);
+2 -2
View File
@@ -82,13 +82,13 @@ export function ssh(host: ISshHostInfo, command: string, sshPath?: string, jumpH
function localForwardToArgs(localForward: ISshLocalForwardInfo): string[] {
// Do not combine error checking and arg conversion for clarity.
if (localForward.localSocket && (localForward.bindAddress || localForward.port)) {
throw Error(localize('local.forward.local.conflict', '"localSocket" cannot be specifed at the same time with "bindAddress" or "port" in localForwards'));
throw Error(localize('local.forward.local.conflict', '"localSocket" cannot be specified at the same time with "bindAddress" or "port" in localForwards'));
}
if (!localForward.localSocket && !localForward.port) {
throw Error(localize('local.forward.local.missing', '"port" or "localSocket" required in localForwards'));
}
if (localForward.remoteSocket && (localForward.host || localForward.hostPort)) {
throw Error(localize('local.forward.remote.conflict', '"remoteSocket" cannot be specifed at the same time with "host" or "hostPort" in localForwards'));
throw Error(localize('local.forward.remote.conflict', '"remoteSocket" cannot be specified at the same time with "host" or "hostPort" in localForwards'));
}
if (!localForward.remoteSocket && (!localForward.host || !localForward.hostPort)) {
throw Error(localize('local.forward.remote.missing', '"host" and "hostPort", or "remoteSocket" required in localForwards'));
+1 -1
View File
@@ -51,7 +51,7 @@ export function showPasswordInputBox(
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const msg: string = user ? localize('ssh.enter.password.for.user', 'Enter password for user "{0}"', user) : localize('ssh_message_enterPassword', 'Enter password');
const msg: string = user ? localize('ssh.enter.password.for.user', 'Enter password for user "{0}"', user) : localize('ssh.message.enter.password', 'Enter password');
return showInputBox(msg, prompt, cancelToken);
}
+30 -30
View File
@@ -14,27 +14,27 @@ import { parse } from 'shell-quote';
const flags: {
[flag: string]: ((entries: { [key: string]: string }, value: string) => void) | null;
} = {
1: entries => (entries.Protocol = '1'),
2: entries => (entries.Protocol = '2'),
4: entries => (entries.AddressFamily = 'inet'),
6: entries => (entries.AddressFamily = 'inet6'),
A: entries => (entries.ForwardAgent = 'yes'),
b: (entries, address) => (entries.BindAddress = address),
C: entries => (entries.Compression = 'yes'),
c: (entries, cipher) => (entries.Cipher = cipher),
D: (entries, address) => (entries.DynamicForward = address),
1: entries => entries.Protocol = '1',
2: entries => entries.Protocol = '2',
4: entries => entries.AddressFamily = 'inet',
6: entries => entries.AddressFamily = 'inet6',
A: entries => entries.ForwardAgent = 'yes',
b: (entries, address) => entries.BindAddress = address,
C: entries => entries.Compression = 'yes',
c: (entries, cipher) => entries.Cipher = cipher,
D: (entries, address) => entries.DynamicForward = address,
// -e (escape code) is used as it's not useful for us and could mess with script execution
e: null,
// -F (config file) is irrelevant
F: null,
// -f (running in background) would interfere with execution
f: null,
g: entries => (entries.GatewayPorts = 'yes'),
I: (entries, device) => (entries.SmartcardDevice = device),
i: (entries, identity) => (entries.IdentityFile = identity),
J: (entries, address) => (entries.ProxyJump = address),
K: entries => (entries.GSSAPIAuthentication = 'yes'),
k: entries => (entries.GSSAPIDelegateCredentials = 'no'),
g: entries => entries.GatewayPorts = 'yes',
I: (entries, device) => entries.SmartcardDevice = device,
i: (entries, identity) => entries.IdentityFile = identity,
J: (entries, address) => entries.ProxyJump = address,
K: entries => entries.GSSAPIAuthentication = 'yes',
k: entries => entries.GSSAPIDelegateCredentials = 'no',
L: (entries, args) => {
/**
* For the cases of:
@@ -49,7 +49,7 @@ const flags: {
return;
} else {
throw new CommandParseError(
`LocalFoward needs a listener and a destination separate by a colon. ${args} does not match.`
`LocalForward needs a listener and a destination separate by a colon. ${args} does not match.`
);
}
}
@@ -63,15 +63,15 @@ const flags: {
const delimiter: number = args.indexOf(':');
if (delimiter === -1) {
throw new CommandParseError(
`LocalFoward needs a listener and a destination separate by a colon. ${args} does not match.`
`LocalForward needs a listener and a destination separate by a colon. ${args} does not match.`
);
}
entries.LocalForward = `${args.substring(0, delimiter)} ${args.substring(delimiter + 1)}`;
},
l: (entries, user) => (entries.User = user),
M: entries => (entries.ControlMaster = 'yes'),
m: (entries, specs) => (entries.MACs = specs),
l: (entries, user) => entries.User = user,
M: entries => entries.ControlMaster = 'yes',
m: (entries, specs) => entries.MACs = specs,
// -N (don't execute remote command) would interfere with execution
N: null,
// -n (redirect stdin) would interfere with execution
@@ -86,11 +86,11 @@ const flags: {
entries[option.slice(0, delimiter)] = option.slice(delimiter + 1);
},
p: (entries, port) => (entries.Port = port),
p: (entries, port) => entries.Port = port,
// -q (quiet mode) not useful for us
q: null,
R: (entries, address) => (entries.RemoteForward = address),
S: (entries, path) => (entries.ControlPath = path),
R: (entries, address) => entries.RemoteForward = address,
S: (entries, path) => entries.ControlPath = path,
// -s (remote subsystem invocation), no setting in the config for this
s: null,
// -T (disable pseudo tty), no setting in the config for this
@@ -99,12 +99,12 @@ const flags: {
t: null,
// -V (display the version) not relevant for us
V: null,
v: entries => (entries.LogLevel = 'verbose'),
W: (entries, address) => (entries.RemoteForward = address),
w: (entries, value) => (entries.TunnelDevice = value),
X: entries => (entries.ForwardX11 = 'yes'),
x: entries => (entries.ForwardX11 = 'no'),
Y: entries => (entries.ForwardX11Trusted = 'yes'),
v: entries => entries.LogLevel = 'verbose',
W: (entries, address) => entries.RemoteForward = address,
w: (entries, value) => entries.TunnelDevice = value,
X: entries => entries.ForwardX11 = 'yes',
x: entries => entries.ForwardX11 = 'no',
Y: entries => entries.ForwardX11Trusted = 'yes',
// output logging
y: null
};
@@ -177,7 +177,7 @@ function parseFlags(input: string[], entries: { [key: string]: string }): number
// eslint-disable-next-line no-constant-condition
while (true) {
const next: void | IParsedOption = parser.getopt();
const next: IParsedOption | undefined = parser.getopt();
if (!next) {
break;
}
+1 -1
View File
@@ -47,7 +47,7 @@ export async function getSshConfigHostInfos(): Promise<Map<string, ISshConfigHos
for (const configPath of getSshConfigurationFiles()) {
const config: Configuration = await getSshConfiguration(configPath);
const hosts: { [host: string]: string } = extractHostNames(config);
Object.keys(hosts).forEach(name => (hostInfos.set(name, { hostName: hosts[name], file: configPath })));
Object.keys(hosts).forEach(name => hostInfos.set(name, { hostName: hosts[name], file: configPath }));
}
return hostInfos;
@@ -0,0 +1,46 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { is } from '../System/guards';
import { ConstructorReturn, Reject, Resolve, AsyncConstructor } from '../System/types';
export function Async<TClass extends new (...args: ConstructorParameters<TClass>) => ConstructorReturn<TClass>>(ctor: TClass) {
class AsyncConstructed extends Promise<TClass> {
static class: TClass = ctor;
constructor(...args: ConstructorParameters<TClass>);
constructor(...args: any[]) {
if (args.length === 1 && typeof args[0] === 'function') {
// this is being called because a new Promise is being created for an async function invocation (not user code)
super(args[0]);
return;
}
// this is being called because a user is creating an instance of the class, and we want to call the init() method
super((resolve: Resolve<TClass>, reject: Reject) => {
try {
// call the constructor with the arguments that they provided
const instance = new ctor(...(args as any)) as any;
// if .init is a function, call it
const pInit = typeof instance.init === 'function' ? instance.init(...args) : instance.init;
// if the result of .init is a promise (or is a promise itself), then on completion, it should propogate the result (or error) to the promise
if (is.promise(pInit)) {
pInit.then(() => resolve(instance)).catch(reject);
} else {
// otherwise, the result of init is not a promise (or it didn't have an init), so just resolve the promise with the result
resolve(instance);
}
} catch (error) {
// if the constructor throws, we should reject the promise with that error.
reject(error);
}
});
}
}
// return a new constructor as a type that creates a Promise<T>
return AsyncConstructed as any as AsyncConstructor<TClass>;
}
+53
View File
@@ -0,0 +1,53 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { is } from '../System/guards';
import { Reject, Resolve } from '../System/types';
type WithInit<TOutput> = TOutput & { init?(...args: any[]): any | Promise<any> };
export function Factory<TFactory extends (...args: Parameters<TFactory>) => ReturnType<TFactory>>(factory: TFactory): new (...args: Parameters<TFactory>) => Promise<Awaited<ReturnType<TFactory>>> {
/** calls/awaits any .init in the result from the factory */
async function initialize(instance: WithInit<ReturnType<TFactory>> | Promise<WithInit<ReturnType<TFactory>>>, args: any[]) {
if (instance !== null && instance !== undefined) {
if (is.promise(instance)) {
instance = await instance;
}
// if .init is a function, call it, if it's a promise, await it
const pInit = typeof instance.init === 'function' ? instance.init(args) : instance.init;
if (is.promise(pInit)) {
await pInit;
}
}
return instance;
}
class AsyncFactory extends Promise<ReturnType<TFactory>> {
protected factory: TFactory;
constructor(...args: any[]) {
if (args.length === 1 && typeof args[0] === 'function') {
// this is being called because a new Promise is being created for an async function invocation (not user code)
super(args[0]);
this.factory = factory;
return;
}
// this is being called because a user is creating an instance of the class, and we want to call the init() method
super((resolve: Resolve<ReturnType<TFactory>>, reject: Reject) => {
try {
// call the factory with the arguments that they provided, then initialize it
initialize(factory(...(args as any)) as any, args).then(resolve).catch(reject);
} catch (error) {
// if the constructor throws, we should reject the promise with that error.
reject(error);
}
});
this.factory = factory;
}
}
return AsyncFactory as any as new (...args: Parameters<TFactory>) => Promise<Awaited<ReturnType<TFactory>>>;
}
+177
View File
@@ -0,0 +1,177 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { is } from '../System/guards';
import { Signal } from './signal';
/** an async foreach function to iterate over any iterable/async iterable, calling a function on each item in parallel as possible */
export async function foreach<T, TResult>(items: undefined | Iterable<T> | Promise<Iterable<T> | undefined> | Promise<undefined> | AsyncIterable<T> | Promise<AsyncIterable<T>>, predicate: (item: T) => Promise<TResult>): Promise<TResult[]> {
items = is.promise(items) ? await items : items; // unwrap the promise if it is one
if (items) {
const result = [] as Promise<TResult>[];
if (is.asyncIterable(items)) {
for await (const item of items) {
result.push(predicate(item)); // run the predicate on each item
}
} else {
for (const item of items) {
result.push(predicate(item)); // run the predicate on each item
}
}
return Promise.all(result);
}
return []; // return an empty array if there is nothing to iterate over
}
interface Cursor<T> {
identity: number;
iterator: AsyncIterator<T>;
result?: IteratorResult<T>;
}
/** An AsyncIterable wrapper that caches so that it can be iterated multiple times */
export function reiterable<T>(iterable: AsyncIterable<T>): AsyncIterable<T> {
const cache = new Array<T>();
let done: boolean | undefined;
let nextElement: undefined | Promise<IteratorResult<T>>;
return {
[Symbol.asyncIterator]() {
let index = 0;
return {
async next() {
if (index < cache.length) {
return { value: cache[index++], done: false };
}
if (done) {
return { value: undefined, done: true };
}
index++;
if (!is.promise(nextElement)) {
nextElement = iterable[Symbol.asyncIterator]().next().then(element => {
if (!(done = element.done)) {
cache.push(element.value);
}
nextElement = undefined;
return element;
});
}
return nextElement;
}
};
}
};
}
export type AsynchIterable<T> = AsyncIterable<T> & {
add(...iterables: (Some<T> | undefined | Promise<T> | Promise<undefined | T>)[]): void;
complete(): void;
autoComplete(shouldAutocomplete: boolean): AsynchIterable<T>;
reiterable(): AsyncIterable<T>;
};
export function accumulator<T>(...iterables: Some<T>[]): AsynchIterable<T> {
const iterators = new Map<number, Promise<Cursor<T>>>();
let completeWhenEmpty = iterables.length > 0; // if we are given any items, they we auto-complete when we run out (so an add after the last item is yielded will throw)
const signal = new Signal<boolean>();
const result = combiner(iterables) as unknown as AsynchIterable<T>;
result.add = (...iterables: (Some<T> | undefined | Promise<undefined | T>)[]) => {
for (const iterable of iterables) {
iterators.set(iterators.size + 1, awaitNext({ identity: iterators.size + 1, iterator: asyncOf(iterable)[Symbol.asyncIterator]() }));
}
signal.resolve(true);
};
result.autoComplete = (shouldAutocomplete: boolean) => { completeWhenEmpty = shouldAutocomplete; return result; };
result.complete = () => signal.dispose(completeWhenEmpty = true);
result.reiterable = () => reiterable(result);
return result;
async function awaitNext(element: Cursor<T>): Promise<Cursor<T>> {
element.result = undefined; // drop the previous result before awaiting the next
element.result = await element.iterator.next();
return element;
}
async function* combiner(iterables: Some<T>[]) {
iterables.forEach((iterable, index) => iterators.set(index, awaitNext({ identity: index, iterator: asyncOf(iterable)[Symbol.asyncIterator]() })));
// Loop until all iterators are done, removing them as they complete
do {
if (!iterators.size && !completeWhenEmpty) {
await signal; // wait for a new item to be added, or for the complete signal
}
while (iterators.size) {
const element = await race([...iterators.values()]);
// Is that iterator done?
if (element.result!.done) {
iterators.delete(element.identity);
continue;
}
// Yield the result from the iterator, and await the next item
const { value } = element.result!;
iterators.set(element.identity, awaitNext(element));
if (value !== undefined && value !== null) {
yield value;
}
}
} while (!completeWhenEmpty);
signal.dispose(false);
// prevent any more iterators from being added
result.add = () => { throw new Error('AsyncIterable is finished'); };
}
}
export type Some<T> = T | Promise<T> | AsyncIterable<T | undefined> | AsyncIterable<Promise<T> | Promise<undefined>> | Iterable<T> | Iterable<Promise<T>>;
export async function* asyncOf<T>(...items: (undefined | Promise<undefined> | Some<T>)[]): AsyncIterable<NonNullable<T>> {
if (is.asyncIterable(items)) {
for await (const item of items) {
if (is.asyncIterable(item) || is.iterable(item)) {
yield* item as any;
continue;
}
yield item as any;
}
return;
}
for (const item of items) {
// skip undefined
if (item) {
if (is.asyncIterable(item) || is.iterable(item)) {
yield* item as any;
continue;
}
yield item as any;
}
}
}
/**
* A substitute for Promise.race()
*
* This is used so that when there is a global function called 'addMisbehavingPromise' present
* it will call that function with the promise returned from Promise.race(...)
* otherwise it just falls back to Promise.race()
*
* This allows unit tests to trap and display 'multiple resolve' errors (Promise.race can look like multiple resolves, but it isn't)
*
* By using this race function instead, we can ignore those (the v8 JIT will easily optimize this out in production)
*/
export function race(promises: Promise<any>[]): Promise<any> {
const addMisbehavingPromise: <T>(p: Promise<T>) => Promise<T> = (global as any).addMisbehavingPromise;
return addMisbehavingPromise ? addMisbehavingPromise(Promise.race(promises)) : Promise.race(promises);
}
+25
View File
@@ -0,0 +1,25 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { is } from '../System/guards';
class Lazy<T> extends Promise<T> {
#promise!: Promise<T>;
constructor(private initializer: T | (() => Promise<T>) | (() => T) | (new () => T)) {
super(resolve => resolve(undefined as any));
}
override then<TResult1 = T, TResult2 = never>(onfulfilled?: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>): Promise<TResult1 | TResult2> {
return (this.#promise ??= Promise.resolve(typeof this.initializer === 'function' ? is.Constructor(this.initializer) ? new this.initializer() : (this.initializer as () => T | Promise<T>)() : this.initializer)).then(onfulfilled, onrejected);
}
override catch(onrejected?: (reason: any) => never): Promise<T> {
return (this.#promise ??= Promise.resolve(typeof this.initializer === 'function' ? is.Constructor(this.initializer) ? new this.initializer() : (this.initializer as () => T | Promise<T>)() : this.initializer)).catch(onrejected);
}
}
/** Returns a promise from a value (value/lambda/constructor) that isn't resolved until is is awaited. */
export function lazy<T>(initializer: T | (() => Promise<T>) | (() => T) | (new () => T)): Promise<T> {
return new Lazy(initializer);
}
+88
View File
@@ -0,0 +1,88 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { is } from '../System/guards';
export class AsyncMap<TKey, TValue> {
private readonly map = new Map<TKey, TValue | Promise<TValue | undefined> | undefined>();
clear(): void {
return this.map.clear();
}
delete(key: TKey): boolean {
return this.map.delete(key);
}
get(key: TKey): TValue | Promise<TValue | undefined> | undefined {
return this.map.get(key);
}
has(key: TKey): boolean {
return this.map.has(key);
}
get size(): number {
return this.map.size;
}
async *entries(): AsyncIterable<[TKey, TValue]> {
// eslint-disable-next-line prefer-const
for (let [key, value] of this.map.entries()) {
if (is.promise(value)) {
value = await value;
}
if (!is.nullish(value)) {
yield [key, value];
}
}
}
keys(): Iterator<TKey> {
return this.map.keys();
}
async *values(): AsyncIterable<TValue > {
for (let value of this.map.values()) {
if (is.promise(value)) {
value = await value;
}
if (!is.nullish(value)) {
yield value;
}
}
}
[Symbol.asyncIterator](): AsyncIterable<[TKey, TValue]> {
return this.entries();
}
getOrAdd(key: TKey, initializer: TValue | Promise<TValue> | Promise<undefined> | (() => Promise<TValue | undefined> | TValue | undefined)): Promise<TValue | undefined> | TValue | undefined {
let result: Promise<TValue | undefined> | TValue | undefined = this.map.get(key);
// if we don't get a match, then we'll try to set the value with the initializer
if (is.nullish(result)) {
// if the initializer is a function, then we'll call it to get the value
if (is.function(initializer)) {
result = initializer();
}
// if we're not handed a promise or a value, then we're done
if (is.nullish(result)) {
return undefined;
}
// set the value in the map to the result of the initializer
this.map.set(key, result);
// if the initializer is a promise, then we'll tack on a bit of logic to remove the value from the map if the promise resolves to undefined
if (is.promise(result)) {
return result.then(v => {
if (is.nullish(v)) {
this.map.delete(key);
}
return v;
});
}
}
return result;
}
set(key: TKey, value: Promise<TValue> | TValue): this {
this.map.set(key, value);
return this;
}
}
+14 -8
View File
@@ -67,9 +67,11 @@ export class Signal<T> implements Promise<T>, Resolveable<T> {
* @param value
*/
resolve(value: T): Resolveable<T> {
const p = this.promise;
this.promise = new ManualPromise<T>();
p.resolve(value);
if (!this.isCompleted) {
const p = this.promise;
this.promise = new ManualPromise<T>();
p.resolve(value);
}
return this;
}
@@ -80,13 +82,17 @@ export class Signal<T> implements Promise<T>, Resolveable<T> {
* @param value
*/
reject(reason: any) {
const p = this.promise;
this.promise = new ManualPromise<T>();
p.reject(reason);
if (!this.isCompleted) {
const p = this.promise;
this.promise = new ManualPromise<T>();
p.reject(reason);
}
return this;
}
dispose() {
this.promise.resolve();
dispose(value?: T) {
if (!this.isCompleted) {
this.promise.resolve(value);
}
}
}
+6 -1
View File
@@ -3,7 +3,12 @@
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { setTimeout as after } from 'timers/promises';
import { setTimeout as after, setImmediate } from 'timers/promises';
/** pause for a number of milliseconds */
export const sleep = after as (msec: number) => Promise<void>;
/** enqueue the call to the callback function to happen on the next available tick, and return a promise to the result */
export function then<T>(callback: () => Promise<T> | T): Promise<T> {
return setImmediate().then(callback);
}
+5 -3
View File
@@ -8,13 +8,15 @@ import { returns } from './returns';
import { sleep } from './sleep';
/** wait on any of the promises to resolve, or if the timeout is reached, throw */
export async function timeout(msecs: number, ...promises: Promise<any>[]): Promise<any> {
export async function timeout(msecs: number, ...promises: Thenable<any>[]): Promise<any> {
// get a promise for the timeout
const t = sleep(msecs).then(() => fail(`Timeout expired after ${msecs}ms`));
// wait until either the timout expires or one of the promises resolves
await Promise.race([t, ...promises]);
// wait until either the timeout expires or one of the promises resolves
const result = await Promise.race([t, ...promises]);
// tag the timeout with a catch to prevent unhandled rejection
t.catch(returns.undefined);
return result;
}
@@ -0,0 +1,62 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { is } from '../System/guards';
import { hierarchy } from '../System/info';
import { getOrAdd } from '../System/map';
import { smash } from '../Text/identifiers';
import { ArbitraryObject } from './interfaces';
const ignore = new Set(['Object', 'Emitter']);
/** A set of descriptors for describing the context of an Event Emitter */
export class Descriptors extends Map<string, Set<string>> {
static none = new Descriptors();
constructor(instance?: ArbitraryObject, descriptors?: Record<string, string | string[] | Set<string>>) {
super();
if (instance) {
if (instance instanceof Descriptors) {
// inherit whatever is in that instance
instance.forEach((value, key) => this.add(key, ...value));
} else {
// add all of the class names of the instance to the set of descriptors
for (const c of hierarchy(instance)) {
if (!ignore.has(c)) {
this.add(c, '');
}
}
}
}
// add the specified descriptors
if (descriptors) {
Object.getOwnPropertyNames(descriptors).forEach(key => {
const value = descriptors[key];
if (!(value instanceof Function)) {
const v = descriptors[key];
if (is.array(v)) {
this.add(key, ...v);
} else if (is.string(v)) {
this.add(key, v);
}
}
});
}
}
override get(key: string): Set<string> | undefined {
return super.get(smash(key));
}
add(key: string, ...values: string[]) {
if (values.length) {
const set = getOrAdd(this, smash(key), () => new Set<string>());
values.forEach(each => set.add(each));
}
}
}
@@ -0,0 +1,501 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/unified-signatures */
import { readFile } from 'node:fs/promises';
import { ManualPromise } from '../Async/manualPromise';
import { ManualSignal } from '../Async/manualSignal';
import { returns } from '../Async/returns';
import { filepath } from '../Filesystem/filepath';
import { hasErrors } from '../Sandbox/interfaces';
import { Sandbox } from '../Sandbox/sandbox';
import { collectGarbage } from '../System/garbageCollector';
import { is } from '../System/guards';
import { isAnonymousObject, members, typeOf } from '../System/info';
import { getOrAdd } from '../System/map';
import { verbose } from '../Text/streams';
import { Descriptors } from './descriptor';
import { parse } from './eventParser';
import { ArbitraryObject, Callback, Continue, EventData, EventStatus, Subscriber, Subscription, Unsubscribe } from './interfaces';
interface Event<TInput = any, TResult = void> {
readonly name: string;
readonly descriptors: Descriptors;
completed?: ManualPromise<EventStatus | TResult>;
readonly variableArgs: any[];
source?: ArbitraryObject;
data?: TInput;
text?: string;
}
const sandbox = new Sandbox();
const syncHandlers = new Map<string, Subscriber[]>();
const asyncHandlers = new Map<string, Subscriber[]>();
const queue = new Array<Event<any, any>>();
const current = new Set<Callback>();
export const DispatcherBusy = new ManualSignal<void>();
/** starts the processing of the event queue. */
async function drain() {
DispatcherBusy.reset();
let event: Event | undefined;
// eslint-disable-next-line no-cond-assign
while (event = queue.shift()) {
await dispatch(event);
}
DispatcherBusy.resolve();
}
/** dispatch the applicable handlers for an event */
async function dispatch<TResult>(event: Event<any, TResult>): Promise<void> {
// check the sync handlers first
let resultValue: EventStatus | TResult | undefined = Continue;
// sync handlers run and await one at a time
// technically, it's possible for other events to run while a sync handler is running
// but that doesn't make any difference; the sync handler will still run to completion
// before the next handler is dispatched.
for (const [callback, captures] of getHandlers(event, syncHandlers)) {
try {
// keep track of which handlers are currently running
current.add(callback);
// call the callback, collate the result.
let r = callback(event as EventData, ...captures);
r = is.promise(r) ? await r.catch(e => {
console.error(e);
return undefined;
}) : r;
// if it is an event/request (as opposed to a notification), then process it.
if (is.promise(event.completed)) {
// if they returned some kind of value, then use that as the result, otherwise, use the default
resultValue = r as TResult | EventStatus;
if (is.cancelled(resultValue)) {
return event.completed.resolve(resultValue); // the event has been cancelled
}
}
} catch (e: any) {
console.error(e);
// if the handler throws, it isn't a reason to cancel the event
} finally {
// clear the callback from the current set
current.delete(callback);
}
}
// then the async handlers (for events with possible result handling)
if (!is.promise(event.completed)) {
// no event.completed, which means this is a notifier
// since notifiers are not cancellable, we can run them all in parallel
// and they don't need to worry about reentrancy
for (const [callback, captures] of getHandlers(event, asyncHandlers)) {
// call the event handler, but don't await it
// we don't care about the result, and we don't want to block
// (if the handler throws, too bad)
try { void callback(event as EventData, ...captures); } catch (e: any) {
console.error(e);
/* ignore */
}
}
return;
}
// this is an event/request (supports a result or cancellation)
// when these are called, they are permitted to work in parallel, and we await them all at the end
// the first one to respond with a non-Continue result will be the result of the event
// (if a handler wants to cancel the event before others run, it should be marked with 'await' so that it runs first)
const results = new Array<any | Promise<any>>(resultValue);
for (const [callback, captures] of getHandlers(event, asyncHandlers)) {
// keep track of which handlers are currently running
current.add(callback);
// call the event handler, but capture the result
try {
const r = callback(event as EventData, ...captures);
results.push(is.promise(r) ? r.catch(returns.undefined).finally(() => current.delete(callback)) : r);
} catch (e: any) {
// if the handler throws, not our problem.
console.error(e);
} finally {
// we should remove it from the current set
current.delete(callback);
}
}
// wait for all the async handlers to complete
// and return the first result that isn't 'Continue'
return event.completed.resolve((await Promise.all(results)).find((each: any) => each !== Continue));
}
function* getHandlers<TResult>(event: Event<any, TResult>, category: Map<string, Subscriber[]>): Iterable<[Callback, string[]]> {
if (category.size === 0) {
return;
}
loop:
for (const subscriber of [...category.get(event.name) || [], ...category.get('*') || []]) {
if (current.has(subscriber.handler)) {
// the current callback is executing, and is (either directly or indirectly) the source of the event
// so, we don't want to execute it again.
continue;
}
// when the subscriber is bound to a specific object, then the source must match
if (subscriber.eventSource && subscriber.eventSource.deref() !== event.source) {
continue;
}
const captures = [] as string[];
// now we can check discriminators to see if they match
for (const [name, discriminator] of subscriber.filters) {
// verify we have a matching descriptor/eventname in the set
// get the descriptor text values
const strings = name === event.name || name === '*' ? [] : event.descriptors.get(name);
if (!strings) {
// the event name isn't a match (or wildcard), and it doesn't have a descriptor with that name
continue loop;
}
if (discriminator === true) {
continue;
}
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
if (!discriminator(event.data || event.source, [...strings, event.text!], captures)) {
// the filter (if it exists) didn't match, so skip this handler
continue loop;
}
}
// looks like we have a match
yield [subscriber.handler, captures];
}
}
const boundSubscribers = new WeakMap<ArbitraryObject, (() => void)[]>();
const autoUnsubscribe = new FinalizationRegistry((unsubscribe: () => void) => {
unsubscribe();
});
export function removeAllListeners(eventSrc: ArbitraryObject) {
if (eventSrc) {
// call unsubscribe
const all = boundSubscribers.get(eventSrc);
if (all) {
verbose(`Unsubscribing all from ${typeOf(eventSrc)}`);
for (const unsubscribe of all) {
unsubscribe();
}
}
autoUnsubscribe.unregister(eventSrc);
collectGarbage();
}
}
/** Subscribe to an event given a trigger expression */
export function on<T>(triggerExpression: string, callback: Callback<T>, eventSrc?: ArbitraryObject): Unsubscribe {
// parse the event expression into a chain of checks
const [isSync, once, filters, eventSource] = parse(triggerExpression, eventSrc);
out:
if ((global as any).DEVMODE && is.emitter(eventSrc)) {
const filterNames = [...filters.keys()];
for (const filterName of filterNames) {
if (eventSrc.isKnownEvent(filterName)) {
break out;
}
}
// this is not always an error (as an emitter may not know about all the events it emits in advance)
// but I like to know if it's happening so I can fix it if I can.
verbose(`Handler with ${filterNames} [${triggerExpression}] has no events in ${typeOf(eventSrc)}`);
}
const subscriber = {
filters,
eventSource: eventSource ? new WeakRef(eventSource) : undefined,
handler: undefined as any
} as Subscriber;
// pick the right subscription map depending on if it is an await call or not
const subscription = isSync ? syncHandlers : asyncHandlers;
for (const eventName of filters.keys()) {
// add the handler to the front of the array for that event
// (since we want newer handlers to run first)
getOrAdd(subscription, eventName, []).unshift(subscriber);
}
// create a function that will remove the handler from the chain
const unsubscribe = () => {
for (const eventName of filters.keys()) {
// remove it from the queue from whence it came
const subscribers = subscription.get(eventName);
if (subscribers) {
const i = subscribers.indexOf(subscriber);
if (i >= 0) {
subscribers.splice(i, 1);
// if there are no more listeners for that handler, remove the array too.
if (subscribers.length === 0) {
subscription.delete(eventName);
}
}
}
}
};
// setup auto unsubscribe when a bound object is garbage collected
if (eventSource) {
autoUnsubscribe.register(eventSource, unsubscribe);
getOrAdd(boundSubscribers, eventSource, []).push(unsubscribe);
}
// set the callback into the handler object (with auto-unsubscribe if it is a 'once' handler)
subscriber.handler = once ? (...args) => { unsubscribe(); return callback(...args); } : callback;
return unsubscribe;
}
/** Subscribe to an event given a trigger expression, only for a single time */
export function once<T>(triggerExpression: string, callback: Callback<T>, eventSrc?: ArbitraryObject): Unsubscribe {
return on(`once ${triggerExpression}`, callback, eventSrc);
}
export function subscribe(subscriber: Record<string, Callback>, options?: { bindAll?: boolean; eventSource?: ArbitraryObject }): Unsubscribe;
export function subscribe(subscriber: string, options?: { folder?: string; bindAll?: boolean; eventSource?: ArbitraryObject; once?: boolean }): Promise<Unsubscribe>;
export function subscribe<T extends Record<string, any>>(subscriber: Promise<Subscription<T>>, options?: { bindAll?: boolean; eventSource?: ArbitraryObject }): Promise<Unsubscribe>;
export function subscribe(subscriber: Record<string, string>, options?: { folder: string; bindAll?: boolean; eventSource?: ArbitraryObject }): Promise<Unsubscribe>;
export function subscribe<T extends Record<string, any>>(subscriber: Subscription<T>, options?: { bindAll?: boolean; eventSource?: ArbitraryObject }): Unsubscribe;
export function subscribe<T extends Record<string, any>>(subscriber: Promise<Subscription<T>> | string | Subscription<T> | Record<string, string>, options: { folder?: string; bindAll?: boolean; eventSource?: ArbitraryObject; once?: boolean } = {}): Unsubscribe | Promise<Unsubscribe> {
if (is.promise(subscriber)) {
return subscriber.then((sub) => subscribe(sub, options));
}
const { properties, fields, methods } = members(subscriber);
if (options.folder) {
subscriber = subscriber as Record<string, string>;
return (async () => { // this has to be async - we may be pulling data from a file...
const unsubs = new Array<Unsubscribe>();
// if a folder is passed in, then we're subscribing to *members* that are strings (either actual function-lets or strings that are the names of files that contain code)
for (const [name, _type] of [...properties, ...fields]) {
// this is a string property, so it might be an event handler
const text = subscriber[name] as string;
try {
const filename = await filepath.isFile(text, options.folder);
if (filename) {
// it is a file, so load it as a function-let
const code = await readFile(filename, 'utf8');
const fn = sandbox.createFunction(code, ['event'], { filename });
if (hasErrors(fn)) {
for (const each of fn) {
console.error(each);
}
throw new Error(`Error loading ${filename}: ${fn}`);
}
unsubs.push(on(options.once ? `once ${name}` : name, fn as Callback, options.eventSource));
continue;
}
// if it's not a file, then treat it as a function-let
const fn = sandbox.createFunction(text, ['event'], { filename: `launch.json/${name}` });
if (hasErrors(fn)) {
for (const each of fn) {
console.error(each);
}
throw new Error(`Error loading ${name}: ${fn}`);
}
unsubs.push(on(options.once ? `once ${name}` : name, fn as Callback, options.eventSource));
} catch (e: any) {
console.error(e);
// if that fails
continue;
}
}
return () => unsubs.forEach((u) => u());
})();
}
// otherwise, we're subscribing to members that are functions
const unsubs = new Array<Unsubscribe>();
for (const [name, info] of methods) {
if (options.bindAll || info.hasNonWordCharacters || isAnonymousObject(subscriber)) {
// subscribe this function, (ensure it's an async function)
unsubs.push(on(options.once ? `once ${name}` : name, info.fn as Callback, options.eventSource));
}
}
return () => unsubs.forEach((u) => u());
}
export function reset() {
syncHandlers.clear();
asyncHandlers.clear();
}
function expandVariableArgs<TInput = any, TResult = void>(variableArgs: any[], event: Event<TInput, TResult>): Event<TInput, TResult> {
const [first, second, third] = variableArgs;
switch (event.variableArgs.length) {
case 0:
event.text = '';
event.data = undefined;
event.source = undefined;
return event;
case 1:
if (typeof first === 'string') {
event.text = first;
} else {
event.text = '';
event.data = first;
}
return event;
case 2:
if (typeof first === 'string') {
event.text = first;
event.data = second;
} else {
if (typeof second === 'string') {
event.text = second;
event.source = first;
event.data = undefined;
} else {
event.text = '';
event.source = first;
event.data = second;
}
}
return event;
case 3:
event.source = first;
event.text = second;
event.data = third;
return event;
}
throw new Error('Invalid number of arguments');
}
function isSubscribed(name: string) {
return syncHandlers.has(name) || asyncHandlers.has(name) || asyncHandlers.has('*') || syncHandlers.has('*');
}
/** adds an event to the queue, to be dispatched when it is unqueued */
export async function emit<TResult>(name: string, descriptors: Descriptors, text: string): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, descriptors: Descriptors, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, descriptors: Descriptors, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, text: string): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string): Promise<TResult | EventStatus>;
export async function emit<TResult>(name: string, ...variableArgs: any[]): Promise<TResult | EventStatus> {
// quickly check if there are any possible handlers for this event
if (isSubscribed(name)) {
const descriptors = variableArgs[0] instanceof Descriptors ? variableArgs.shift() : Descriptors.none;
// create a promise that will be resolved when the event is dispatched
const result = new ManualPromise<TResult | EventStatus>();
// add the event to the queue
queue.push(expandVariableArgs(variableArgs, { name, variableArgs, descriptors, completed: result }));
// if the queue was empty, start it draining the queue
if (DispatcherBusy.isCompleted) {
void drain(); // don't wait for the queue to finish draining
}
// return the promise
return result;
}
return Continue;
}
/** immediately dispatches an event */
export async function emitNow<TResult>(name: string, descriptors: Descriptors, text: string): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, descriptors: Descriptors, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, descriptors: Descriptors, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, text: string): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, text: string, data: ArbitraryObject): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string): Promise<TResult | EventStatus>;
export async function emitNow<TResult>(name: string, ...variableArgs: any[]): Promise<TResult | EventStatus> {
// quickly check if there are any possible handlers for this event
if (isSubscribed(name)) {
const descriptors = variableArgs[0] instanceof Descriptors ? variableArgs.shift() : Descriptors.none;
// create a promise that will be resolved when the event is dispatched
const result = new ManualPromise<TResult | EventStatus>();
// dispatch the event immediately (the result comes from inside the EventDetails)
void dispatch(expandVariableArgs(variableArgs, { name, descriptors, variableArgs, completed: result }));
// return the result promise
return result;
}
return Continue;
}
/** adds an event to the queue, to be dispatched when it is unqueued */
export function notify(name: string, descriptors: Descriptors, text: string): void;
export function notify(name: string, descriptors: Descriptors, data: ArbitraryObject): void;
export function notify(name: string, descriptors: Descriptors, text: string, data: ArbitraryObject): void;
export function notify(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string): void;
export function notify(name: string, descriptors: Descriptors, source: ArbitraryObject, data: ArbitraryObject): void;
export function notify(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string, data: ArbitraryObject): void;
export function notify(name: string, text: string): void;
export function notify(name: string, text: string, data: ArbitraryObject): void;
export function notify(name: string, data: ArbitraryObject): void;
export function notify(name: string): void;
export function notify(name: string, ...variableArgs: any[]): void {
// quickly check if there are any possible handlers for this event
if (isSubscribed(name)) {
const descriptors = variableArgs[0] instanceof Descriptors ? variableArgs.shift() : Descriptors.none;
// add the event to the queue
queue.push(expandVariableArgs(variableArgs, { name, variableArgs, descriptors }));
// if the queue was empty, start it draining the queue
if (DispatcherBusy.isCompleted) {
void drain(); // don't wait for the queue to finish draining
}
}
}
/** immediately dispatches an event */
export function notifyNow(name: string, descriptors: Descriptors, text: string): void;
export function notifyNow(name: string, descriptors: Descriptors, data: ArbitraryObject): void;
export function notifyNow(name: string, descriptors: Descriptors, text: string, data: ArbitraryObject): void;
export function notifyNow(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string): void;
export function notifyNow(name: string, descriptors: Descriptors, source: ArbitraryObject, data: ArbitraryObject): void;
export function notifyNow(name: string, descriptors: Descriptors, source: ArbitraryObject, text: string, data: ArbitraryObject): void;
export function notifyNow(name: string, text: string): void;
export function notifyNow(name: string, data: ArbitraryObject): void;
export function notifyNow(name: string, text: string, data: ArbitraryObject): void;
export function notifyNow(name: string): void;
export function notifyNow(name: string, ...variableArgs: any[]): void {
// quickly check if there are any possible handlers for this event
if (isSubscribed(name)) {
const descriptors = variableArgs[0] instanceof Descriptors ? variableArgs.shift() : Descriptors.none;
// dispatch the event immediately
void dispatch(expandVariableArgs(variableArgs, { name, descriptors, variableArgs }));
}
}
+279
View File
@@ -0,0 +1,279 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/unified-signatures */
import { is } from '../System/guards';
import { smash } from '../Text/identifiers';
import { Descriptors } from './descriptor';
import { emit, emitNow, notify, notifyNow, on, removeAllListeners, subscribe } from './dispatcher';
import { ArbitraryObject, Callback, Cancelled, Continue, EventStatus, Subscription } from './interfaces';
export interface EventOptions<TOutput = any> {
now?: boolean;
default?: TOutput | Promise<TOutput> | (() => TOutput) | (() => Promise<TOutput>);
cancel?(): TOutput | never;
descriptors?: Record<string, string | string[]>;
once?: boolean;
}
export interface WithDefault<TOutput = any> {
default(): TOutput;
}
export abstract class Emitter {
readonly descriptors = new Descriptors(this);
#knownEvents = new Set<string>();
isKnownEvent(event: string) {
return !!this.#knownEvents.has(event);
}
/** adds an event to the queue, to be dispatched when it is unqueued */
protected async emit(event: string, text: string): Promise<EventStatus>;
protected async emit(event: string, data: ArbitraryObject): Promise<EventStatus>;
protected async emit(event: string, text: string, data: ArbitraryObject): Promise<EventStatus>;
protected async emit(event: string, tOrD: any, data?: ArbitraryObject): Promise<EventStatus> {
return data ?
emit(event, this.descriptors, this, tOrD, data) :
emit(event, this.descriptors, this, tOrD);
}
/** immediately dispatches an event */
protected async emitNow(event: string, text: string): Promise<EventStatus>;
protected async emitNow(event: string, data: ArbitraryObject): Promise<EventStatus>;
protected async emitNow(event: string, text: string, data: ArbitraryObject): Promise<EventStatus>;
protected async emitNow(event: string, tOrD: any, data?: ArbitraryObject): Promise<EventStatus> {
return data ?
emitNow(event, this.descriptors, this, tOrD, data) :
emitNow(event, this.descriptors, this, tOrD);
}
/** adds a notification event to the queue, to be dispatched when it is unqueued */
protected notify(event: string, text: string): void;
protected notify(event: string, data: ArbitraryObject): void;
protected notify(event: string, text: string, data: ArbitraryObject): void;
protected notify(event: string, tOrD: any, data?: ArbitraryObject): void {
return data ?
notify(event, this.descriptors, this, tOrD, data) :
notify(event, this.descriptors, this, tOrD);
}
/** immediately dispatches a notification event */
protected notifyNow(event: string, text: string): void;
protected notifyNow(event: string, data: ArbitraryObject): void;
protected notifyNow(event: string, text: string, data: ArbitraryObject): void;
protected notifyNow(event: string, tOrD: any, data?: ArbitraryObject): void {
return data ?
notifyNow(event, this.descriptors, this, tOrD, data) :
notifyNow(event, this.descriptors, this, tOrD);
}
/**
* Creates a named event function for triggering events in an {@link Emitter}
*
* @returns the created event trigger function of type `() => Promise<TOutput|EventStatus>`
*
* @remarks When the trigger is invoked, the event handler can return one of the following:
* - {@link Continue} (or `undefined`) - the event is not cancelled, and execution should continue normally.
* - {@link Cancelled} - the event is requested to be cancelled (there is no guarantee however.)
*
* @param eventName - the string name of the event
* @param options - options for the event trigger
*/
protected newEvent(eventName: string, options?: EventOptions): () => Promise<undefined | EventStatus>;
/**
* Creates a named event function for triggering events in an {@link Emitter}
* @template TOutput - the expected output type of of the event handler function.
*
* @returns the created event trigger function of type `() => Promise<TOutput|EventStatus>`
*
* @remarks When the trigger is invoked, the event handler can return one of the following:
* - `<TOutput>` - an value of type `<TOutput>` - the event is not cancelled, and the emitter can use the data returned.
* - {@link Continue} (or `undefined`) - the event is not cancelled, and execution should continue normally.
* - {@link Cancelled} - the event is requested to be cancelled (there is no guarantee however.)
*
* @param eventName - the string name of the event
* @param options - options for the event trigger (default: `{now: false}`)
*/
protected newEvent<TOutput>(eventName: string, options?: EventOptions): () => Promise<TOutput | EventStatus>;
/**
* Creates a named event function for triggering events in an {@link Emitter}
* @template TData - the expected input type of the event handler function.
* @template TOutput - the expected output type of of the event handler function.
*
* @returns the created event trigger function of type `(input:TData) => Promise<TOutput|EventStatus>`
*
* @remarks When the trigger is invoked, the event handler can return one of the following:
* - `<TOutput>` - an value of type `<TOutput>` - the event is not cancelled, and the emitter can use the data returned.
* - {@link Continue} (or `undefined`) - the event is not cancelled, and execution should continue normally.
* - {@link Cancelled} - the event is requested to be cancelled (there is no guarantee however.)
*
* @param eventName - the string name of the event
* @param options - options for the event trigger (default: `{now: false}`)
*/
protected newEvent<TData, TOutput>(eventName: string, options?: EventOptions): (input: TData) => Promise<TOutput | EventStatus>;
/**
* Creates a named event function for triggering events in an {@link Emitter}
* @template TText - a text string that can be used to filter events during subscription
* @template TData - the expected input type of the event handler function.
* @template TOutput - the expected output type of of the event handler function.
*
* @returns the created event trigger function of type `(text: TText, input:TData) => Promise<TOutput|EventStatus>`
*
* @remarks When the trigger is invoked, the event handler can return one of the following:
* - `<TOutput>` - an value of type `<TOutput>` - the event is not cancelled, and the emitter can use the data returned.
* - {@link Continue} (or `undefined`) - the event is not cancelled, and execution should continue normally.
* - {@link Cancelled} - the event is requested to be cancelled (there is no guarantee however.)
*
* @param eventName - the string name of the event
* @param options - options for the event trigger (default: `{now: false}`)
*/
protected newEvent<TText extends string, TData, TOutput>(eventName: string, options?: EventOptions<TOutput>): (text: TText, data: TData) => Promise<TOutput>;
protected newEvent<TOutput>(eventName: string, options?: EventOptions & WithDefault<TOutput>): () => Promise<TOutput>;
protected newEvent<TData, TOutput>(eventName: string, options?: EventOptions & WithDefault<TOutput>): (input: TData) => Promise<TOutput>;
protected newEvent<TText extends string, TData, TOutput>(eventName: string, options?: EventOptions<TOutput> & WithDefault<TOutput>): (text: TText, data: TData) => Promise<TOutput>;
protected newEvent<TText extends string, TData, TOutput>(eventName: string, options?: EventOptions<TOutput> & WithDefault<TOutput>): (text: TText, data: TData) => Promise<EventStatus | TOutput> {
eventName = smash(eventName);
this.#knownEvents.add(eventName);
const descriptors = options?.descriptors ? new Descriptors(this.descriptors, options.descriptors) : this.descriptors;
// is it an immediate event?
if (options?.now) {
return async (input?: TText, data?: TData): Promise<TOutput | EventStatus> => {
switch (options?.once) {
case false:
// already triggered this one time event.
return;
case true:
options.once = false;
}
// trigger the event
const result = await ((data !== undefined) ?
emitNow<TOutput>(eventName, descriptors, this, input || '', data as any) : // text and data
emitNow<TOutput>(eventName, descriptors, this, input || '', input as any)); // text or data (or neither)
return is.cancelled(result) ? // was the event cancelled?
options?.cancel?.() || Cancelled : // the event was cancelled - call the cancel function, or return Cancelled
is.continue(result) ? // was the event continued (handler returned nothing)?
is.function(options?.default) ? // the event is continued, is the default handler a function?
options?.default() : // the default is a function, call it.
options?.default || Continue : // the default is a value, call it (or just return Continue)
result as TOutput; // the event was not cancelled, and the handler returned a value.
};
}
// otherwise queue it
return async (input?: TText, data?: TData): Promise<TOutput | EventStatus> => {
switch (options?.once) {
case false:
// already triggered this one time event.
return;
case true:
options.once = false;
}
// trigger the event
const result = await ((data !== undefined) ?
emit<TOutput>(eventName, descriptors, this, input || '', data as any) : // text and data
emit<TOutput>(eventName, descriptors, this, input || '', input as any)); // text or data (or neither)
return is.cancelled(result) ? // was the event cancelled?
options?.cancel?.() || Cancelled : // the event was cancelled - call the cancel function, or return Cancelled
is.continue(result) ? // was the event continued (handler returned nothing)?
is.function(options?.default) ? // the event is continued, is the default handler a function?
options?.default() : // the default is a function, call it.
options?.default || Continue : // the default is a value, call it (or just return Continue)
result as TOutput; // the event was not cancelled, and the handler returned a value.
};
}
/** notification with event name, but no data in the event. */
protected newNotification(eventName: string, options?: EventOptions): () => void;
/** notification with event name, and some data (of <TData>) */
protected newNotification<TData>(eventName: string, options?: EventOptions): (input: TData) => void;
/** notification with an event name, an event string <TInput>, and some data<TData> */
protected newNotification<TText extends string, TData>(eventName: string, options?: EventOptions): (text: TText, data: TData) => void;
protected newNotification<TText extends string, TData>(eventName: string, options?: EventOptions): (text: TText, data: TData) => void {
eventName = smash(eventName);
this.#knownEvents.add(eventName);
const descriptors = options?.descriptors ? new Descriptors(this.descriptors, options.descriptors) : this.descriptors;
// is it an immediate event?
if (options?.now) {
return (input?: TText, data?: TData): void => {
switch (options.once) {
case false:
// already triggered this one time event.
return;
case true:
options.once = false;
}
// trigger the event
return (data !== undefined) ?
notifyNow(eventName, descriptors, this, input || '', data as any) : // text and data
notifyNow(eventName, descriptors, this, input || '', input as any); // text or data (or neither)
};
}
// otherwise queue it
return (input?: TText, data?: TData): void => {
switch (options?.once) {
case false:
// already triggered this one time event.
return;
case true:
options.once = false;
}
// trigger the event
return (data !== undefined) ?
notify(eventName, descriptors, this, input || '', data as any) : // text and data
notify(eventName, descriptors, this, input || '', input as any); // text or data (or neither)
};
}
/** subscribe to events (assumes 'this' modifier, and handler is filtered to the instance) */
on(eventExpression: string, callback: Callback) {
return on(`this ${eventExpression}`, callback, this);
}
/** subscribe to events (assumes 'this' modifier, and handler is filtered to the instance) */
once(eventExpression: string, callback: Callback) {
return on(`this once ${eventExpression}`, callback, this);
}
/** subscribe directly to events on this object */
subscribe(): void;
subscribe<T>(...subscribers: string[]): Promise<void>;
subscribe<T extends Record<string, any>>(...subscribers: Subscription<T>[]): void;
subscribe<T extends Record<string, any>>(...subscribers: string[] | Subscription<T>[]): void | Promise<void> {
if (subscribers.length === 0) {
return subscribe(this as unknown as Subscription, { eventSource: this }) && undefined;
}
if (typeof subscribers[0] === 'string') {
return Promise.all(subscribers.map(each => subscribe(each as string, { eventSource: this }))) as unknown as Promise<void>;
}
for (const each of subscribers as ArbitraryObject[]) {
subscribe(each, { eventSource: this });
}
}
removeAllListeners() {
removeAllListeners(this);
}
wait(eventExpression: string, _timeout?: number): Promise<void> {
return new Promise<void>((e: () => void) => this.on(eventExpression, e));
}
}
@@ -0,0 +1,262 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { hasErrors } from '../Sandbox/interfaces';
import { Sandbox } from '../Sandbox/sandbox';
import { first } from '../System/array';
import { smash } from '../Text/identifiers';
import { Kind, Scanner, Token } from '../Text/scanner';
import { verbose } from '../Text/streams';
import { ArbitraryObject, Filter } from './interfaces';
/* eslint-disable @typescript-eslint/no-non-null-assertion */
// ensure that array gets the first function, we need it for the discriminator
// eslint-disable-next-line no-unused-expressions
first;
function isKeyword(token: Token) {
return token.kind > Kind.KeywordsStart && token.kind < Kind.KeywordsEnd;
}
export function parse(triggerExpression: string, sourceToBindTo: ArbitraryObject | undefined): [boolean, boolean, Map<string, Filter | true>, ArbitraryObject?] {
//
// [modifiers] event[filter]:discriminator[filter]/discriminator[filter]/discriminator[filter]...
//
const scanner = new Scanner(triggerExpression).start();
let token: Token;
let once: boolean = false;
let source: any;
let isSync = false;
// drop any leading whitespace
scanner.takeWhiteSpaceAndNewLines();
// grab modifiers off the front
while (isKeyword(token = scanner.take())) {
switch (token.kind) {
case Kind.OnceKeyword:
once = true;
break;
case Kind.ThisKeyword:
source = sourceToBindTo;
break;
case Kind.AwaitKeyword:
isSync = true;
break;
default:
throw new Error(`unexpected keyword ${token.kind}`);
}
scanner.takeWhiteSpaceAndNewLines();
}
const filters = new Map<string, Filter | true>(); // <name, filterFn>
function addFilter(name: string) {
scanner.takeWhiteSpaceAndNewLines();
token = scanner.take();
if (token.kind === Kind.OpenBracket) {
// has a filter expression of some kind.
filters.set(name, generateFilterFn(scanner));
token = scanner.take();
} else {
// if there isn't a filter, then we just need to add a filter with 'true'
filters.set(name, true);
}
scanner.takeWhiteSpaceAndNewLines();
return token.kind === Kind.EndOfFile;
}
processing:
do {
switch (token.kind) {
case Kind.EndOfFile:
break processing;
case Kind.Slash:
// separator - skip this token (we can skip over multiple slashes, it's ok...)
token = scanner.take();
continue;
case Kind.Asterisk:
// match any event name
if (addFilter('*')) {
break processing;
}
break;
case Kind.Identifier:
if (addFilter(smash(token.text))) {
break processing;
}
break;
case Kind.OpenBracket:
// filter without event or discriminator name
filters.set('*', generateFilterFn(scanner));
token = scanner.take();
break;
case Kind.Whitespace:
continue processing;
default:
throw new Error(`unexpected token ${JSON.stringify(token)}`);
}
if (token.kind === Kind.EndOfFile) {
break;
}
// if the token isn't a separator or end of file, then it is an error
if (token.kind !== Kind.Slash) {
throw new Error(`unexpected token ${JSON.stringify(token)}`);
}
// eslint-disable-next-line no-constant-condition
} while (true);
// for each discriminator[filter]
// get the descriptor name
// get the filter value
// the filter expression is a JavaScript expression. (special case: if a regex is a part of the expression, it's assumed to be applied against the text of the event data)
if (sourceToBindTo !== source) {
verbose(`source specified but 'this' not found in handler name or expression for '${triggerExpression}' `);
}
return [isSync, once, filters, source];
}
const sandbox = new Sandbox();
function generateFilterFn(scanner: Scanner): Filter {
// take all the tokens until we hit a closing bracket
const inner = [...scanner.takeUntil(Kind.CloseBracket, {
nestable: [[Kind.OpenBracket, Kind.CloseBracket]],
escape: [Kind.Backslash]
})];
// a filter expression is one or more of:
// - a regular expression
// - a JavaScript expression
// separated by && or ||
const expression = new Array<string>();
// remove leading whitespace
eatWhitespace(inner);
outer:
while (inner.length) {
eatWhitespace(inner);
let token = inner.shift()!;
switch (token.kind) {
case Kind.Slash: {
// regular expression
// take all tokens until we hit a slash that isn't escaped
const rxExpression = [token];
while (inner.length) {
token = inner.shift()!;
rxExpression.push(token); // store this token as part of the regex
switch (token.kind) {
case Kind.Slash:
// now see if there are any flags
if (inner.length) {
token = inner[0];
if (token.kind === Kind.Identifier) {
rxExpression.push(inner.shift()!);
}
}
// at this point, we should have the whole regex.
// turn this into an expression that tests against any $strings
expression.push(`(!!$strings.find( ($text)=> { const r = ${rxExpression.map(token => token.text).join('')}.exec($text); if( r ) { $captures.push( ...r ); return true; } } ))`);
continue outer;
case Kind.Backslash:
// take the next token, and add it to the regex
rxExpression.push(inner.shift()!);
continue;
}
// if we have nothing left, and we haven't closed the regex, then it's an error
if (!inner.length) {
throw new Error(`unterminated regular expression ${inner}`);
}
}
}
break;
case Kind.OpenParen:
case Kind.CloseParen:
case Kind.BarBar:
case Kind.AmpersandAmpersand:
// add that token to the final expression
expression.push(token.text!);
break;
case Kind.StringLiteral:
// if we're given a string literal and the next token after that is one of {||, &&, ]}
// then we can just use the string literal as a comparison
// otherwise it should be part of the JavaScript expression (i.e. ['foo'===bar])
eatWhitespace(inner);
const peek = inner[0];
if (peek) {
switch (peek.kind) {
case Kind.BarBar:
case Kind.AmpersandAmpersand:
case Kind.CloseBracket:
expression.push(`$strings.has(${token.text!})`);
continue outer;
}
}
// eslint-disable-next-line no-fallthrough
default:
// anything else, take all the tokens until we hit a separator/terminator/the end
const js = [token];
while (inner.length) {
token = inner.shift()!;
switch (token.kind) {
case Kind.BarBar:
case Kind.AmpersandAmpersand:
case Kind.CloseBracket:
// push the token back on the stack, and we're done
inner.unshift(token);
break;
default:
js.push(token);
continue;
}
break;
}
const jsExpression = js.map(each => each.text).join('');
// sandbox style, assumes $data is set to Event.data and $strings is the collection of strings for the discriminator or the event itself
expression.push(jsExpression.trim());
break;
}
}
// $data - either the event data or the event source object if there is no event data.
// $strings - a set of string values to match a regex with.
const fn = sandbox.createFunction<Filter>(`try { with($data) return ${expression.join(' ')} } catch ($e) { return false; }`, ['$data', '$strings', '$captures']);
if (hasErrors(fn)) {
throw new Error(`invalid filter expression: ${expression.join(' ')}`);
}
return fn;
}
function eatWhitespace(tokens: Token[]) {
while (tokens.length && tokens[0].kind === Kind.Whitespace) {
tokens.shift();
}
}
@@ -0,0 +1,47 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export interface EventData<TInput = any | undefined> {
readonly name: string;
completed?: Promise<unknown>;
readonly source?: ArbitraryObject;
readonly data: TInput;
readonly text: string;
}
export interface Descriptor {
name: string;
values?: string[];
}
export type Unsubscribe = () => void;
export type Callback<TOutput = unknown> = (event: EventData<TOutput>, ...args: any[]) => Promise<TOutput> | Promise<EventStatus> | Promise<undefined> | TOutput | EventStatus | undefined | Promise<void>;
export type PickByType<T, TKeepType> = {
[P in keyof T as T[P] extends TKeepType ? P : never]: T[P]
};
export type Subscription<T extends Record<string, any> = Record<string, any>> = PickByType<T, Callback | string>;
export type ArbitraryObject = Record<string, any>;
export type EventStatus = 'Cancelled' | undefined;
export const Cancelled = 'Cancelled';
export const Continue = undefined;
export type Filter = ($data: ArbitraryObject, $strings: string[], $captures: string[]) => boolean;
export interface Subscriber {
/** the filter checks generated from the event registration */
filters: Map<string, Filter | true>;
/** the source (aka 'this') value that must match if the handler is tied to an object */
eventSource?: WeakRef<ArbitraryObject>;
/** the event handler function itself */
handler: Callback<any>;
}
+48
View File
@@ -0,0 +1,48 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/naming-convention */
export class requests {
static readonly select = 'select';
static readonly get = 'get';
}
// [noun]-[verb]
export class events {
static readonly writing = 'writing';
static readonly reading = 'reading';
}
// output channel notifications
export class channels {
static readonly debug = 'debug';
static readonly verbose = 'verbose';
static readonly info = 'info';
static readonly warning = 'warning';
static readonly error = 'error';
static readonly internal = 'internal';
}
/** Notifications */
// [state]
// [pastTenseVerb]-[noun]
export class notifications {
static readonly ready = 'ready';
static readonly exited = 'exited';
static readonly started = 'started';
static readonly stopped = 'stopped';
static readonly connected = 'connected';
static readonly disconnected = 'disconnected';
static readonly read = 'read'; // past-tense, so it's not confused with the reading verb
static readonly wrote = 'wrote'; // past-tense, so it's not confused with the writing verb
static readonly message = 'message';
}
/** Queries expect a value in return */
export class queries {
static readonly selectBinary = 'select-binary';
}
@@ -0,0 +1,140 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { basename, delimiter, extname, join, normalize as norm, resolve } from 'path';
import { fail } from 'assert';
import { randomBytes } from 'crypto';
import { constants, Stats } from 'fs';
import { stat } from 'fs/promises';
import { tmpdir } from 'os';
import { isWindows } from '../../constants';
import { returns } from '../Async/returns';
import { is } from '../System/guards';
export const normalize = isWindows ? (p: string) => norm(p).toLowerCase().replace(/^([a-z]\:)/, ($1) => $1.toUpperCase()) : norm;
export function pathsFromVariable(environmentVariable: string = 'PATH'): string[] {
return process.env[environmentVariable]?.split(delimiter) || [];
}
export async function filterToFolders(paths: string[]): Promise<string[]> {
const set = new Set(paths);
for (const each of [...set.keys()]) {
if (!each || !await filepath.isFolder(each)) {
set.delete(each);
}
}
return [...set.keys()];
}
export interface Entry {
name: string;
fullPath: string;
isFolder: boolean;
isFile: boolean;
isLink: boolean;
}
export interface File extends Entry {
extension: string;
basename: string;
isFolder: false;
isFile: true;
isExecutable: boolean;
size: number;
}
export interface Folder extends Entry {
isFolder: true;
isFile: false;
isExecutable: false;
}
// eslint-disable-next-line @typescript-eslint/naming-convention
export class filepath {
static async stats(name: string | undefined | Promise<string | undefined>, baseFolder?: string): Promise<[string, Stats | undefined] | [undefined, undefined]> {
if (is.promise(name)) {
name = await name;
}
// if the value isn't a string or has a newline, it ain't a file name
if (!name || name.indexOf('\n') !== -1) {
return [undefined, undefined];
}
// if we've been given a baseFolder, expand that, otherwise just normalize the value.
name = baseFolder ? resolve(baseFolder, name) : normalize(name);
return [name, await stat(name).catch(returns.undefined)];
}
static async info(name: string | undefined | Promise<string | undefined>, baseFolder?: string, executableExtensions: Set<string> = process.platform === 'win32' ? new Set(['.exe'/* ,'.cmd','.bat' */]) : new Set()): Promise<undefined | File | Folder> {
const [fullPath, stats] = await filepath.stats(name, baseFolder);
if (!stats) {
return undefined;
}
// create the entry
const entry = {
name: basename(fullPath),
fullPath,
isFolder: stats.isDirectory(),
isFile: stats.isFile(),
isLink: stats.isSymbolicLink()
} as File | Folder;
if (entry.isFile) {
entry.size = stats.size;
if (isWindows) {
const fp = fullPath.toLowerCase();
entry.extension = extname(fp);
entry.basename = basename(fp, entry.extension);
entry.isExecutable = executableExtensions.has(entry.extension);
return entry;
}
entry.extension = extname(fullPath);
entry.basename = basename(fullPath, entry.extension);
// eslint-disable-next-line no-bitwise
entry.isExecutable = !!(stats.mode & (constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH));
return entry;
}
if (entry.isFolder) {
return entry;
}
fail(new Error(`Unexpected file type for ${fullPath}`));
}
static async isFile(name: any | string | undefined | Promise<string | undefined>, baseFolder?: string): Promise<undefined | string> {
const [fullName, stats] = await filepath.stats(name, baseFolder);
return stats?.isFile() ? fullName : undefined;
}
static async isFolder(name: string | undefined | Promise<string | undefined>, baseFolder?: string): Promise<undefined | string> {
const [fullName, stats] = await filepath.stats(name, baseFolder);
return stats?.isDirectory() ? fullName : undefined;
}
static async exists(name: string | undefined | Promise<string | undefined>, baseFolder?: string): Promise<undefined | string> {
const [fullName, stats] = await filepath.stats(name, baseFolder);
return stats ? fullName : undefined;
}
static async isExecutable(name: string | undefined | Promise<string | undefined>, baseFolder?: string): Promise<undefined | string> {
const info = await filepath.info(name, baseFolder);
return info?.isFile && info.isExecutable ? info.fullPath : undefined;
}
static parent(name: Promise<string | undefined>): Promise<string | undefined>;
static parent(name: string | undefined): string | undefined;
static parent(name: string | undefined | Promise<string | undefined>): string | undefined | Promise<string | undefined> {
return is.promise(name) ? name.then(filepath.parent) : name ? normalize(resolve(name, '..')) : undefined;
}
}
export function tmpFile(prefix = 'tmp.', suffix = '.tmp', folder = tmpdir()) {
return join(folder, prefix + randomBytes(32).toString('hex') + suffix);
}
+223
View File
@@ -0,0 +1,223 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/unified-signatures */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { Dirent, constants } from 'fs';
import { readdir, stat } from 'fs/promises';
import { basename, extname, sep } from 'path';
import { isWindows } from '../../constants';
import { accumulator, foreach } from '../Async/iterators';
import { ManualPromise } from '../Async/manualPromise';
import { returns } from '../Async/returns';
import { is } from '../System/guards';
import { File, Folder, normalize } from './filepath';
interface FolderWithChildren extends Folder {
children?: Map<string, File | FolderWithChildren>;
}
const cache = new Map<string, File | FolderWithChildren | Promise<FolderWithChildren | undefined>>();
/**
* This reads a directory and returns a map of the files and folders in it
* It is quite tolerant of errors and reentrancy, so if multiple callers are trying to get the same results
* it will only do the work once per directory
*
* @param fullPath the full path of the folder to read
* @param executableExtensions a set of file extensions that are considered executable on Windows
* @returns a map of the files and folders in the directory, or undefined if the directory doesn't exist or is inaccessible.
*/
async function readDirectory(fullPath: string, executableExtensions: Set<string> = process.platform === 'win32' ? new Set(['.exe'/* ,'.cmd','.bat' */]) : new Set()): Promise<Map<string, File | FolderWithChildren> | undefined> {
// have we already read this directory?
let folder = cache.get(fullPath) as FolderWithChildren | undefined;
let promise: ManualPromise<FolderWithChildren | undefined> | undefined;
if (!folder) {
// create a promise and insert it into the cache, so if something else comes looking before we do any async, they can await that
promise = new ManualPromise<FolderWithChildren | undefined>();
cache.set(fullPath, promise);
const stats = await stat(fullPath).catch(returns.undefined);
if (!stats?.isDirectory()) {
// no results, return undefined.
promise.resolve(folder);
return undefined;
}
folder = {
name: basename(fullPath),
fullPath,
isFolder: true,
isFile: false,
isLink: stats.isSymbolicLink()
} as FolderWithChildren;
}
// if we are waiting on a promise
if (is.promise(folder)) {
folder = await folder;
}
// if the target isn't a folder, it can't have children
if (!folder?.isFolder) {
return undefined;
}
// if we haven't scanned this folder yet, do so now.
if (!folder.children) {
folder.children = new Map();
if (!is.promise(promise)) {
// if we didn't already have a promise, create one now.
// this can happen when the parent has scanned and added in the child but nobody has asked for the children yet.
promise = new ManualPromise<FolderWithChildren | undefined>();
cache.set(fullPath, promise);
}
// this doesn't use the path.info function because in this case, the direntry is already available, and on Windows we can skip a call to stat (which is expensive)
// process all the entries, and add them to the cache and the children map
await foreach(readdir(fullPath, { withFileTypes: true }).catch(returns.none), async (direntry: Dirent) => {
const name = direntry.name;
const fp = `${fullPath}${sep}${name}`;
if (cache.has(fp)) {
return;
}
// create the entry
const entry = {
name,
fullPath: fp,
isFolder: direntry.isDirectory(),
isFile: direntry.isFile(),
isLink: direntry.isSymbolicLink()
} as File | FolderWithChildren;
if (entry.isFile) {
if (isWindows) {
entry.extension = extname(name.toLowerCase());
entry.isExecutable = executableExtensions.has(entry.extension);
entry.basename = basename(name, entry.extension);
} else {
entry.basename = basename(name);
// in non-Windows platforms, we need to check the file mode to see if it's executable.
const stats = await stat(entry.fullPath).catch(returns.undefined);
if (!stats) {
return;
}
// eslint-disable-next-line no-bitwise
entry.isExecutable = !!(stats.mode & (constants.S_IXUSR | constants.S_IXGRP | constants.S_IXOTH));
entry.extension = extname(name);
}
}
// attach the child to the parent
(folder as FolderWithChildren).children!.set(name, entry);
// keep the child in the cache too.
cache.set(entry.fullPath, entry);
});
cache.set(fullPath, folder as FolderWithChildren);
if (!promise!.isResolved) {
promise!.resolve(folder as FolderWithChildren);
}
}
return folder.children;
}
export async function scanFolder(folder: string, scanDepth: number, filePredicate?: (file: File) => Promise<boolean> | boolean, folderPredicate?: (folder: FolderWithChildren) => Promise<boolean> | boolean, files = accumulator<string>()): Promise<void> {
// should not have depth less than 0
if (scanDepth < 0) {
return;
}
// normalize the folder
folder = normalize(folder);
// if we have already visited this folder, return
await foreach(readDirectory(folder), async ([_name, entry]) => {
if (entry.isFile) {
if (!filePredicate || await filePredicate(entry)) {
files.add(entry.fullPath);
}
return;
}
if (scanDepth && entry.isFolder && (!folderPredicate || await folderPredicate(entry))) {
await scanFolder(entry.fullPath, scanDepth - 1, filePredicate, folderPredicate, files);
}
});
}
/** The Finder searches paths to find executable given a name or regular expression.
*
* It can scan multiple paths, and can be configured to exclude folders.
* It can also scan into subfolders of the given folders to a specified depth.
*
*/
export class Finder implements AsyncIterable<string> {
#excludedFolders = new Set<string | RegExp>(['winsxs', 'syswow64', 'system32']);
#files = accumulator<string>().autoComplete(false);
files = this.#files.reiterable();
private match: (file: File) => Promise<boolean> | boolean;
private promises = new Array<Promise<void>>();
constructor(executableName: string);
constructor(executableRegEx: RegExp);
constructor(fileMatcher: (file: File) => Promise<boolean> | boolean);
constructor(binary: string | RegExp | ((file: File) => Promise<boolean> | boolean)) {
switch (typeof binary) {
case 'string':
this.match = (file: File) => file.isExecutable && file.basename === binary;
break;
case 'function':
this.match = binary;
break;
case 'object':
this.match = (file: File) => file.isExecutable && !!file.basename.match(binary);
break;
}
}
static resetCache() {
cache.clear();
}
exclude(folder: string) {
this.#excludedFolders.add(folder);
}
/**
* Add one or more locations to scan, with an optionally specified depth.
*
* The scanning of those locations begins immediately and is done asynchronously.
*
*/
scan(...location: (Promise<string> | string)[]): Finder;
scan(depth: number, ...location: (Promise<string> | string)[]): Finder;
scan(...location: (Promise<string> | string | number)[]): Finder {
const depth = typeof location[0] === 'number' ? location.shift() as number : 0;
this.promises.push(...location.map(each => scanFolder(each.toString(), depth, this.match, (f) => !this.#excludedFolders.has(f.name), this.#files)));
return this;
}
[Symbol.asyncIterator](): AsyncIterator<string> {
this.#files.complete();
return this.#files[Symbol.asyncIterator]();
}
get results(): Promise<Set<string>> {
return Promise.all(this.promises).then(async () => {
const result = new Set<string>();
for await (const file of this) {
result.add(file);
}
return result;
});
}
}
+147
View File
@@ -0,0 +1,147 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
import { strict } from 'assert';
import { existsSync } from 'fs';
import { accumulator } from '../Async/iterators';
import { logAndReturn } from '../Async/returns';
import { Process } from '../Process/process';
import { ProcessFunction, Program } from '../Process/program';
import { Instance } from '../System/types';
import { filepath } from './filepath';
let ripgrep: Instance<ProcessFunction> | undefined;
export async function initRipGrep(filename: string) {
if (!ripgrep) {
const rg = await filepath.isExecutable(filename);
strict(rg, `File ${filename} is not executable`);
ripgrep = await new Program(filename);
}
}
export class FastFinder implements AsyncIterable<string> {
private keepOnlyExecutables: boolean;
private executableExtensions = new Array<string>();
private processes = new Array<Instance<Process>>();
private pending = 0;
private readyToComplete = false;
private distinct = new Set<string>();
#files = accumulator<string>().autoComplete(false);
[Symbol.asyncIterator](): AsyncIterator<string> {
this.readyToComplete = true;
if (this.pending === 0) {
this.#files.complete();
}
return this.#files[Symbol.asyncIterator]();
}
constructor(private fileGlobs: string[], options?: { executable?: boolean; executableExtensions?: string[] }) {
strict(ripgrep, 'initRipGrep must be called before using FastFinder');
this.keepOnlyExecutables = options?.executable ?? false;
if (this.keepOnlyExecutables && process.platform === 'win32') {
this.executableExtensions = options?.executableExtensions ?? ['.exe', '.bat', '.cmd', '.ps1'];
}
}
/**
* Add one or more locations to scan, with an optionally specified depth.
*
* The scanning of those locations begins immediately and is done asynchronously.
*
*/
scan(...location: string[]): FastFinder;
scan(depth: number, ...location: string[]): FastFinder;
scan(...location: (string | number)[]): FastFinder {
const depth = (typeof location[0] === 'number' ? location.shift() as number : 0) + 1;
const globs = this.executableExtensions.length ?
this.fileGlobs.map(glob => this.executableExtensions.map(ext => glob.includes('**') ? glob : `**/${glob}${ext}`)).flat() :
this.fileGlobs.map(glob => glob.includes('**') ? glob : `**/${glob}`);
// only search locations that exist
location = location.filter(each => existsSync(each.toString()));
// only search if there are globs and locations to search
if (globs.length && location.length) {
this.pending++;
void ripgrep!(...globs.map(each => ['--glob', each]).flat(), '--max-depth', depth, '--null-data', '--no-messages', '-L', '--files', ...location.map(each => each.toString())).then(async proc => {
const process = proc as unknown as Instance<Process>;
this.processes.push(process);
for await (const line of process.stdio) {
if (this.distinct.has(line)) {
continue;
}
this.distinct.add(line);
if (!this.keepOnlyExecutables || await filepath.isExecutable(line)) {
this.#files.add(line);
}
}
}).catch(logAndReturn.undefined).finally(() => {
this.pending--;
if (this.readyToComplete && this.pending === 0) {
this.#files.complete();
}
});
}
return this;
}
}
interface MatchData {
path: {
text: string;
};
lines: {
text: string;
};
line_number: number;
absolute_offset: number;
submatches: unknown[];
}
interface RipGrepMatch {
type: 'match';
data: MatchData;
}
function isMatch(obj: Record<string, any>): obj is RipGrepMatch {
return obj.type === 'match' && obj.data.path && obj.data.lines;
}
/** Calls RipGrep looking for strings */
export async function* ripGrep(target: string, regex: string, options?: { glob?: string; binary?: boolean; encoding?: 'utf-16' | 'utf-8'; ignoreCase?: boolean }): AsyncGenerator<MatchData> {
strict(ripgrep, 'initRipGrep must be called before using ripGrep');
const optionalArguments = new Array<string>();
if (options?.binary) {
optionalArguments.push('--binary');
}
if (options?.encoding) {
optionalArguments.push('-E', options.encoding);
}
if (options?.glob) {
optionalArguments.push('--iglob', options.glob);
}
if (options?.ignoreCase) {
optionalArguments.push('--ignore-case');
}
regex = regex.replace(/\?\</g, '\?P<');
const proc = await ripgrep(regex, '--null-data', '--json', '--no-messages', ...optionalArguments, target);
for await (const line of proc.stdio) {
try {
const obj = JSON.parse(line);
if (isMatch(obj)) {
yield obj.data;
}
} catch {
// skip deserialization errors.
}
}
}
@@ -0,0 +1,245 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { spawnSync } from 'child_process';
import { OperatingSystem } from '../../constants';
import { resolveEnvironmentVariables } from '../System/environment';
function windows(argsString: string): string[] {
argsString = resolveEnvironmentVariables(argsString);
const result: string[] = [];
let currentArg: string = "";
let isInQuote: boolean = false;
let wasInQuote: boolean = false;
let i: number = 0;
while (i < argsString.length) {
let c: string = argsString[i];
if (c === '\"') {
if (!isInQuote) {
isInQuote = true;
wasInQuote = true;
++i;
continue;
}
// Need to peek at next character.
if (++i === argsString.length) {
break;
}
c = argsString[i];
if (c !== '\"') {
isInQuote = false;
}
// Fall through. If c was a quote character, it will be added as a literal.
}
if (c === '\\') {
let backslashCount: number = 1;
let reachedEnd: boolean = true;
while (++i !== argsString.length) {
c = argsString[i];
if (c !== '\\') {
reachedEnd = false;
break;
}
++backslashCount;
}
const still_escaping: boolean = (backslashCount % 2) !== 0;
if (!reachedEnd && c === '\"') {
backslashCount = Math.floor(backslashCount / 2);
}
while (backslashCount--) {
currentArg += '\\';
}
if (reachedEnd) {
break;
}
// If not still escaping and a quote was found, it needs to be handled above.
if (!still_escaping && c === '\"') {
continue;
}
// Otherwise, fall through to handle c as a literal.
}
if (c === ' ' || c === '\t' || c === '\r' || c === '\n') {
if (!isInQuote) {
if (currentArg !== "" || wasInQuote) {
wasInQuote = false;
result.push(currentArg);
currentArg = "";
}
i++;
continue;
}
}
currentArg += c;
i++;
}
if (currentArg !== "" || wasInQuote) {
result.push(currentArg);
}
return result;
}
function posix(argsString: string): string[] {
// inspired by https://github.com/migueldeicaza/mono-wasm-libc/blob/96eaa7afc23cd675358595e1dd6ab4b6c8f9f07f/src/misc/wordexp.c#L32
let doubleQuote = false;
let singleQuote = false;
let paren = 0;
let brace = 0;
let arg = '';
let args = ['printf', `%s\\\\n`];
for (let i = 0; i < argsString.length; ++i) {
const char = argsString[i];
const next = argsString[i + 1];
switch (char) {
case '\\':
if (!singleQuote) {
if (next === '\\') {
arg += '\\\\\\\\';
++i;
continue;
}
arg += `\\${next}`;
++i;
continue;
}
break;
case '\'':
if (!doubleQuote) {
singleQuote = !singleQuote;
}
arg += "'";
continue;
case '"':
if (!singleQuote) {
doubleQuote = !doubleQuote;
}
arg += '"';
continue;
case '(':
if (!singleQuote && !doubleQuote) {
++paren;
}
break;
case ')':
if (!singleQuote && !doubleQuote) {
--paren;
}
break;
case '}':
if (!singleQuote && !doubleQuote && !brace) {
throw new Error(`Unsupported character: ${char}`);
}
brace--;
break;
case '\n':
case '|':
case '&':
case ';':
case '<':
case '>':
case '{':
if (!singleQuote && !doubleQuote) {
throw new Error(`Unsupported character: ${char}`);
}
break;
case '$':
if (!singleQuote) {
if (next === '(') {
if (argsString[i + 2] === '(') {
paren += 2;
i += 2;
arg += '$((';
continue;
}
throw new Error(`Nested Commands not supported`);
}
if (next === '{') {
arg += '${';
brace++;
i++;
continue;
}
}
break;
case '`':
if (!singleQuote) {
throw new Error(`Nested Commands not supported`);
}
break;
case ' ':
case '\t':
if (doubleQuote || singleQuote || paren || brace) {
break;
}
if (arg.length > 0) {
args.push(arg);
arg = '';
}
continue;
}
arg += char;
}
if (arg.length > 0) {
args.push(arg);
}
args = args.map(s => {
if (s.startsWith(`'`) && s.endsWith(`'`)) {
return `"${s}"`;
}
if (s.startsWith('$[') && s.endsWith(']')) {
return `${s}`;
}
return `'${s}'`;
});
if (paren !== 0) {
throw new Error(`Unbalanced parenthesis`);
}
if (singleQuote || doubleQuote) {
throw new Error(`Unbalanced quotes`);
}
if (brace) {
throw new Error(`Unbalanced braces`);
}
const r = spawnSync(`eval`, args, {shell: process.env['SHELL'] || true});
if (r.error || r.status !== 0) {
throw new Error('Failed to parse command line');
}
const txt = r.stdout.toString();
const result = txt.split('\n');
result.length--;
return result;
}
/** parses a command line out of a string and produces an array of strings
*
* handles quotes, escapes, and environment variables
*/
export function extractArgs(argsString: string): string[] {
argsString = argsString.trim();
switch (OperatingSystem) {
case 'win32':
return windows(argsString);
case 'linux':
case 'darwin':
case 'freebsd':
case 'openbsd':
return posix(argsString);
}
throw new Error(`Unsupported OS: ${OperatingSystem}`);
}

Some files were not shown because too many files have changed in this diff Show More