Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62614d8fa8 | ||
|
|
fecfc08451 | ||
|
|
62a03c2b21 | ||
|
|
7273d6112b | ||
|
|
74bddb82e5 | ||
|
|
4af6ca9db0 | ||
|
|
7e4ee25c48 | ||
|
|
6da9a49652 | ||
|
|
51d88dbb24 | ||
|
|
cd8ecf9060 | ||
|
|
847ea0b73c | ||
|
|
68c7be9d9e | ||
|
|
1bde544458 | ||
|
|
f62cad6a2f | ||
|
|
eec372a186 | ||
|
|
b98bb40a89 | ||
|
|
4d1a2a0e90 | ||
|
|
dec50598bc | ||
|
|
c5c64ad831 | ||
|
|
27153190e2 | ||
|
|
2cc55ea6eb | ||
|
|
121a657acb | ||
|
|
6a54986b3f | ||
|
|
b4a70dfc0a | ||
|
|
efa5c2244b | ||
|
|
4199155228 | ||
|
|
d949d93924 | ||
|
|
44e2a0ec4c | ||
|
|
0cd369c603 | ||
|
|
76fce67276 | ||
|
|
f3e0f0bb05 | ||
|
|
628301be37 | ||
|
|
6efaafef60 | ||
|
|
f387815749 | ||
|
|
c873aa18bd | ||
|
|
78a8ff3bb3 | ||
|
|
3033657a19 | ||
|
|
ac118f453b | ||
|
|
9e10a71ffb | ||
|
|
4525bd0ed5 | ||
|
|
89d0a7a01f | ||
|
|
27cd52a1b9 | ||
|
|
e020a75bb7 | ||
|
|
c8a7776222 | ||
|
|
3934ef89ea |
Generated
+3257
-95
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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'
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
*.js
|
||||
test/**/index.ts
|
||||
test/**/runTest.ts
|
||||
tools/prepublish.js
|
||||
|
||||
dist/
|
||||
vscode*.d.ts
|
||||
|
||||
+13
-3
@@ -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",
|
||||
|
||||
@@ -34,3 +34,4 @@ localized_string_ids.h
|
||||
src/nativeStrings.ts
|
||||
|
||||
vscode*.d.ts
|
||||
.scripts/_*
|
||||
|
||||
@@ -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}'`);
|
||||
}
|
||||
}
|
||||
@@ -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" } });
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
+10
-15
@@ -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();
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
@@ -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('');
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "node16",
|
||||
"moduleResolution": "node16",
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"allowSyntheticDefaultImports": true,
|
||||
"sourceMap": true,
|
||||
"esModuleInterop": true
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
Vendored
+102
-102
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
Vendored
+18
-3
@@ -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",
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
Vendored
+15
-193
@@ -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
@@ -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/
|
||||
|
||||
@@ -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
|
||||
@@ -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
@@ -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.
|
||||
|
||||
|
||||
---------------------------------------------------------
|
||||
|
||||
-------------------------------------------------------------------
|
||||
|
||||
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3558
-3518
File diff suppressed because it is too large
Load Diff
+3558
-3518
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
+3559
-3519
File diff suppressed because it is too large
Load Diff
@@ -16,7 +16,7 @@
|
||||
"Type": "git",
|
||||
"Git": {
|
||||
"RepositoryUrl": "https://github.com/lldb-tools/lldb-mi",
|
||||
"CommitHash": "2388bd74133bc21eac59b2e2bf97f2a30770a315"
|
||||
"CommitHash": "4fe9c663edce2447e114c71851694d8c529b982d"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-138
@@ -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();
|
||||
});
|
||||
|
||||
@@ -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
@@ -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
@@ -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."
|
||||
}
|
||||
|
||||
@@ -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) ? ", " : ".");
|
||||
});
|
||||
|
||||
@@ -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}`;
|
||||
}
|
||||
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -17,5 +17,6 @@ export interface TextEdit {
|
||||
}
|
||||
|
||||
export interface WorkspaceEdit {
|
||||
changes: { [uri: string]: TextEdit[] };
|
||||
file: string;
|
||||
edits: TextEdit[];
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>();
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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>>>;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 }));
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -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
Reference in New Issue
Block a user