Compare commits

...
29 Commits
Author SHA1 Message Date
Sean McManus 16b4710f8c Merge pull request #9561 from microsoft/seanmcm/revert2DeploySteps
Revert deploy steps
2022-07-08 12:54:25 -07:00
Sean McManus 3d58b640f0 Fix changelog version. 2022-07-08 11:45:23 -07:00
Sean McManus a5b573dbcd Update changelog for 1.11.2 2022-07-08 11:43:49 -07:00
Sean McManus 9360987d31 Revert "Revert "Add deploySteps and variables to cppdbg (#9418)""
This reverts commit 8914e28c26.
2022-07-08 11:42:09 -07:00
Sean McManus 08776b77f7 Merge pull request #9557 from microsoft/seanmcm/revertDeplaySteps
revert deploy steps
2022-07-07 18:55:50 -07:00
Sean McManus b34766054b Remove changelog entry. 2022-07-07 18:48:05 -07:00
Sean McManus 8914e28c26 Revert "Add deploySteps and variables to cppdbg (#9418)"
This reverts commit b55a98c697.
2022-07-07 18:46:31 -07:00
Sean McManus 2a39dc402a Merge pull request #9550 from microsoft/main
Merge for 1.11.1
2022-07-07 15:55:09 -07:00
xisui-MSFT b55a98c697 Add deploySteps and variables to cppdbg (#9418)
* Add deploySteps and variables to cppdbg
2022-07-06 19:55:39 -07:00
Sean McManus 08b9c995bd Update changelog for 1.11.1 (#9549) 2022-07-06 17:56:43 -07:00
Colen Garoutte-Carson 6da34e4236 Display a log message when intelliSenseMode is Disabled (#9543) 2022-07-06 17:50:34 -07:00
Sean McManus e172440607 Fix cl.exe being excluded for .c files and c/cpp caching. (#9544)
* Fix cl.exe being excluded for .c files and c/cpp caching.
2022-07-06 15:23:30 -07:00
Colen Garoutte-Carson 996453b3a8 Fix issue in which duplicate compiler args might be used in compiler query (#9532) 2022-07-01 11:44:44 -07:00
Colen Garoutte-Carson 0eb68d22a0 Update changelog to reflect reverted change (#9523) 2022-06-29 12:39:40 -07:00
Colen Garoutte-Carson a2a8d77445 Revert "Reduce default C++ inlay hint font size 12 to match VS and potentially reduce confusion (#9480)" (#9522)
This reverts commit a2683630e0.
2022-06-29 12:35:05 -07:00
Sean McManus 032d9a288e Update changelog for 1.11.1 (#9517) 2022-06-28 21:19:40 -07:00
Sean McManus 59ea146b6e Change C_Cpp.debugShortcut to resource scope (#9514)
Make C_Cpp.debugShortcut resource scope.
2022-06-28 20:57:31 -07:00
Sean McManus 09a1ce1e8a Update ThirdPartyNotices.txt (#9516)
* Update ThirdPartyNotices.txt
2022-06-28 19:18:23 -07:00
Colen Garoutte-Carson 58a9ec846f Fix issue preventing building with the latest nodejs (#9515) 2022-06-28 16:49:19 -07:00
Sean McManus 6f3ae65833 Add setting to hide leading underscores for inlay hints. (#9500)
* Add setting to hide leading underscores for inlay hints.
2022-06-28 16:25:03 -07:00
Sean McManus a8e6695b55 Add setting to show inlay hints on the left. (#9506) 2022-06-28 14:48:06 -07:00
Chuck Ries c7edc9981f Contribute breakpoints for the "rust" language (#9484)
* Contribute breakpoints for the "rust" language

Since rust code can be debugged with this extension, contribute breakpoints for the "rust" language such that the workaround of "allow breakpoints in all files" is no longer required.
2022-06-28 14:12:20 -07:00
Sean McManus 4d0912eb9d Update yarn.lock. (#9513) 2022-06-28 12:15:52 -07:00
Andrew Wang 7747ac6226 Update VSCode Telemetry Package to v0.6.2 (#9512)
* Update VSCode Telemetry Package to v0.6.2
2022-06-28 11:34:09 -07:00
Elaheh Rashedi 13155149ea rename "success" to "succeeded" in telemetry (#9509) 2022-06-28 10:56:55 -07:00
Sean McManus d3fffbad7b Add setting for & space in inlay hints. (#9502)
* Add setting for & space in inlay hints.
2022-06-24 12:06:36 -07:00
Sean McManus 6fe98d2f54 Add left padding to "auto" inlay hints with no spaces on the left (#9499)
* Add left padding to inlay hint.
2022-06-24 11:13:33 -07:00
Sean McManus a2683630e0 Reduce default C++ inlay hint font size 12 to match VS and potentially reduce confusion (#9480)
* Reduce default inlay hint font size to 12 match VS and reduce confusion.
2022-06-23 17:33:37 -07:00
Sean McManus 590923ca99 Fix remove diagnostics for the disable case. (#9495) 2022-06-23 13:42:44 -07:00
31 changed files with 6150 additions and 3117 deletions
+1
View File
@@ -33,3 +33,4 @@ localized_string_ids.h
# ignore generate files. It will be generated when building
src/nativeStrings.ts
vscode*.d.ts
+27 -1
View File
@@ -1,6 +1,32 @@
# C/C++ for Visual Studio Code Change Log
## Version 1.11.0: June 20, 2022
## Version 1.11.2 (pre-release): July 8, 2022
### Enhancements
* Add deploySteps and variables to cppdbg. [PR #9418](https://github.com/microsoft/vscode-cpptools/pull/9418)
## Version 1.11.1 (pre-release): July 7, 2022
### Enhancements
* Move "auto" inlay hints to the right by default and add `C_Cpp.inlayHints.autoDeclarationTypes.showOnLeft`. [#9478](https://github.com/microsoft/vscode-cpptools/issues/9478)
* Allow breakpoints for Rust debugging. [PR #9484](https://github.com/microsoft/vscode-cpptools/pull/9484)
* Remove `_` from the start of parameter inlay hints and add `C_Cpp.inlayHints.parameterNames.hideLeadingUnderscores`. [#9485](https://github.com/microsoft/vscode-cpptools/issues/9485)
* Add `C_Cpp.inlayHints.referenceOperator.showSpace` setting. [#9486](https://github.com/microsoft/vscode-cpptools/issues/9486)
* Make `C_Cpp.debugShortcut` settable per-workspace folder. [PR #9514](https://github.com/microsoft/vscode-cpptools/pull/9514)
### Bug Fixes
* Fix "unknown register name" IntelliSense error. [#4382](https://github.com/microsoft/vscode-cpptools/issues/4382)
* Fix performance issue with tag parsing a file with a lot of defines. [#6454](https://github.com/microsoft/vscode-cpptools/issues/6454)
* Fix missing logging when `C_Cpp.intelliSenseEngine` is set to `"Disabled"`. [#9277](https://github.com/microsoft/vscode-cpptools/issues/9277)
* Fix the code analysis "disable" option not automatically clearing the disabled diagnostics. [#9364](https://github.com/microsoft/vscode-cpptools/issues/9364)
* Fix `-isystem` not being used for system headers with code analysis. [#9366](https://github.com/microsoft/vscode-cpptools/issues/9366)
* Fix compiler querying for EDG-based compilers. [#9410](https://github.com/microsoft/vscode-cpptools/issues/9410)
* Fix bug with the environment being incorrect when compiler querying. [#9472](https://github.com/microsoft/vscode-cpptools/issues/9472)
* Fix inlay hints not having padding on the left if there is no existing space. [#9479](https://github.com/microsoft/vscode-cpptools/issues/9479)
* Fix duplicate inlay hints appearing sometimes. [#9487](https://github.com/microsoft/vscode-cpptools/issues/9487)
* Fix duplicate compiler args in compiler query with custom configuration providers using cpptools-api prior to v6. [#9531](https://github.com/microsoft/vscode-cpptools/issues/9531)
* Fix cl.exe build tasks not showing for .c files and .c build tasks being cached for .cpp files (and vice versa). [PR #9544](https://github.com/microsoft/vscode-cpptools/pull/9544)
* Fix process launching concurrency issues on Windows.
## Version 1.11.0 (pre-release): June 20, 2022
### New Features
* Add inlay hints for parameters and auto types. [#5845](https://github.com/microsoft/vscode-cpptools/issues/5845)
File diff suppressed because it is too large Load Diff
+906 -34
View File
File diff suppressed because it is too large Load Diff
+34 -2
View File
@@ -166,10 +166,13 @@
"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 /* int */ index = 0;\n```", "comment": [ "Markdown text between `` and the text inside ``` block is code and should not be localized." ] },
"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.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." ] },
@@ -298,6 +301,35 @@
"c_cpp.debuggers.hardwareBreakpoints.description": "Explicit control of hardware breakpoint behavior for remote targets.",
"c_cpp.debuggers.hardwareBreakpoints.require.description": "If true, always use hardware breakpoints. Defaults to false.",
"c_cpp.debuggers.hardwareBreakpoints.limit.description": "Optional limit on the number of available hardware breakpoints to use. Only enforced when \"require\" is true and \"limit\" is greater than 0. Defaults to 0.",
"c_cpp.debuggers.variables.description": "Variables for recursive substitution in this launch configuration. Each variable may refer to others.",
"c_cpp.debuggers.variables.properties.description": "Variable for recursive substitution in this launch configuration. The value may refer to other variables.",
"c_cpp.debuggers.host.description": "Host information.",
"c_cpp.debuggers.host.user.description": "User logging into the host.",
"c_cpp.debuggers.host.hostName.description": "Host name.",
"c_cpp.debuggers.host.port.description": "SSH port on the host. Default is 22.",
"c_cpp.debuggers.host.jumpHost.description": "Connect to the target host by first making a connection to the jump hosts.",
"c_cpp.debuggers.host.localForward.description": "Forward connections to the given TCP port or Unix socket on the local (client) host to the given host and port, or Unix socket, on the remote side",
"c_cpp.debuggers.host.localForward.bindAddress.description": "Local address",
"c_cpp.debuggers.host.localForward.port.description": "Local port",
"c_cpp.debuggers.host.localForward.host.description": "Host name",
"c_cpp.debuggers.host.localForward.hostPort.description": "Host port",
"c_cpp.debuggers.host.localForward.localSocket.description": "Local socket",
"c_cpp.debuggers.host.localForward.remoteSocket.description": "Remote socket",
"c_cpp.debuggers.deploySteps.description": "Steps needed to deploy the application. Order matters.",
"c_cpp.debuggers.deploySteps.scp.description": "Copy files using SCP.",
"c_cpp.debuggers.deploySteps.scp.files.description": "Files to be copied via SCP. Supports path pattern.",
"c_cpp.debuggers.deploySteps.scp.targetDir.description": "Target directory.",
"c_cpp.debuggers.deploySteps.scp.scpPath.description": "Optional full path to SCP. Assumes SCP is on PATH if not specified",
"c_cpp.debuggers.deploySteps.debug": "If true, skip when starting without debugging. If false, skip when starting debugging. If undefined, never skip.",
"c_cpp.debuggers.deploySteps.ssh.description": "SSH command step.",
"c_cpp.debuggers.deploySteps.ssh.command.description": "Command to be executed via SSH. The command after '-c' in SSH command.",
"c_cpp.debuggers.deploySteps.ssh.sshPath.description": "Optional full path to SSH. Assumes SSH is on PATH if not specified",
"c_cpp.debuggers.deploySteps.continueOn.description": "An optional finish pattern in output. When this pattern is seen in the output, continue the deploy procedures regardless of whether this step returns.",
"c_cpp.debuggers.deploySteps.shell.description": "Shell command step.",
"c_cpp.debuggers.deploySteps.shell.command.description": "Shell command to be executed.",
"c_cpp.debuggers.vsCodeCommand.description": "VS Code command to be invoked. Can be a command in VS Code or an active extension.",
"c_cpp.debuggers.vsCodeCommand.command.description": "VS Code command to be invoked.",
"c_cpp.debuggers.vsCodeCommand.args.description": "Arguments to the VS Code command.",
"c_cpp.taskDefinitions.name.description": "The name of the task.",
"c_cpp.taskDefinitions.command.description": "The path to either a compiler or script that performs compilation.",
"c_cpp.taskDefinitions.args.description": "Additional arguments to pass to the compiler or compilation script.",
+197 -20
View File
@@ -23,10 +23,24 @@ import { PlatformInformation } from '../platform';
import { Environment, ParsedEnvironmentFile } from './ParsedEnvironmentFile';
import { CppSettings, OtherSettings } from '../LanguageServer/settings';
import { configPrefix } from '../LanguageServer/extension';
import { expandAllStrings, ExpansionOptions, ExpansionVars } from '../expand';
import { scp, ssh } from '../SSH/commands';
import * as glob from 'glob';
import { promisify } from 'util';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
enum StepType {
scp = 'scp',
ssh = 'ssh',
shell = 'shell',
remoteShell = 'remoteShell',
command = 'command'
}
const globAsync: (pattern: string, options?: glob.IOptions | undefined) => Promise<string[]> = promisify(glob);
/*
* Retrieves configurations from a provider and displays them in a quickpick menu to be selected.
* Ensures that the selected configuration's preLaunchTask (if existent) is populated in the user's task.json.
@@ -38,6 +52,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
private assetProvider: IConfigurationAssetProvider;
// Keep a list of tasks detected by cppBuildTaskProvider.
private static detectedBuildTasks: CppBuildTask[] = [];
private static detectedCppBuildTasks: CppBuildTask[] = [];
private static detectedCBuildTasks: CppBuildTask[] = [];
protected static recentBuildTaskLabel: string;
public constructor(assetProvider: IConfigurationAssetProvider, type: DebuggerType) {
@@ -95,7 +111,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
const selection: ConfigMenu | undefined = await vscode.window.showQuickPick(this.localizeConfigDetail(items), {placeHolder: localize("select.configuration", "Select a configuration")});
if (!selection) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": "debug", "configSource": ConfigSource.unknown, "configMode": ConfigMode.unknown, "cancelled": "true", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": "debug", "configSource": ConfigSource.unknown, "configMode": ConfigMode.unknown, "cancelled": "true", "succeeded": "true" });
return []; // User canceled it.
}
@@ -119,7 +135,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// resolveDebugConfiguration will be automatically called after calling provideDebugConfigurations.
const configs: CppDebugConfiguration[]= await this.provideDebugConfigurations(folder);
if (!configs || configs.length === 0) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile, "configMode": ConfigMode.noLaunchConfig, "cancelled": "true", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": folder ? ConfigSource.workspaceFolder : ConfigSource.singleFile, "configMode": ConfigMode.noLaunchConfig, "cancelled": "true", "succeeded": "true" });
return undefined; // aborts debugging silently
} else {
// Currently, we expect only one debug config to be selected.
@@ -153,9 +169,9 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
try {
await cppBuildTaskProvider.runBuildTask(config.preLaunchTask);
config.preLaunchTask = undefined;
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "true" });
} catch (err) {
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "false" });
Telemetry.logDebuggerEvent(DebuggerEvent.debugPanel, { "debugType": DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "false" });
}
return config;
}
@@ -180,7 +196,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
config.debugType = config.debugType ? config.debugType : DebugType.debug;
const configMode: ConfigMode = isExistingConfig ? ConfigMode.launchConfig : ConfigMode.noLaunchConfig;
// if configuration.debuggerEvent === undefined, it means this configuration is already defined in launch.json and is shown in debugPanel.
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "success": "true" });
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))) {
@@ -203,11 +219,11 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
* This hook is directly called after 'resolveDebugConfiguration' but with all variables substituted.
* This is also ran after the tasks.json has completed.
*
* Try to add all missing attributes to the debug configuration being launched.
* Try to add all missing attributes to the debug configuration being launched.
* If return "undefined", the debugging will be aborted silently.
* If return "null", the debugging will be aborted and launch.json will be opened.
*/
resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult<CppDebugConfiguration> {
*/
async resolveDebugConfigurationWithSubstitutedVariables(folder: vscode.WorkspaceFolder | undefined, config: CppDebugConfiguration, token?: vscode.CancellationToken): Promise<CppDebugConfiguration | null | undefined> {
if (!config || !config.type) {
return undefined; // Abort debugging silently.
}
@@ -230,7 +246,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Disable debug heap by default, enable if 'enableDebugHeap' is set.
if (!config.enableDebugHeap) {
const disableDebugHeapEnvSetting: Environment = {"name" : "_NO_DEBUG_HEAP", "value" : "1"};
const disableDebugHeapEnvSetting: Environment = { "name": "_NO_DEBUG_HEAP", "value": "1" };
if (config.environment && util.isArray(config.environment)) {
config.environment.push(disableDebugHeapEnvSetting);
@@ -243,6 +259,8 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// Add environment variables from .env file
this.resolveEnvFile(config, folder);
await this.expand(config, folder);
this.resolveSourceFileMapVariables(config);
// Modify WSL config for OpenDebugAD7
@@ -305,6 +323,19 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
// logger.showOutputChannel();
}
// Run deploy steps
if (config.deploySteps && config.deploySteps.length !== 0) {
const codeVersion: number[] = vscode.version.split('.').map(num => parseInt(num, undefined));
if ((util.isNumber(codeVersion[0]) && codeVersion[0] < 1) || (util.isNumber(codeVersion[0]) && codeVersion[0] === 1 && util.isNumber(codeVersion[1]) && codeVersion[1] < 69)) {
logger.getOutputChannelLogger().showErrorMessage(localize("vs.code.1.69+.required", "'deploySteps' require VS Code 1.69+."));
return undefined;
}
const deploySucceeded: boolean = await this.deploySteps(config, token);
if (!deploySucceeded || token?.isCancellationRequested) {
return undefined;
}
}
return config;
}
@@ -449,8 +480,44 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
private async loadDetectedTasks(): Promise<void> {
if (!DebugConfigurationProvider.detectedBuildTasks || DebugConfigurationProvider.detectedBuildTasks.length === 0) {
DebugConfigurationProvider.detectedBuildTasks = await cppBuildTaskProvider.getTasks(true);
const editor: vscode.TextEditor | undefined = vscode.window.activeTextEditor;
const emptyTasks: CppBuildTask[] = [];
if (!editor) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
const fileExt: string = path.extname(editor.document.fileName);
if (!fileExt) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
// Don't offer tasks for header files.
const isHeader: boolean = util.isHeaderFile (editor.document.uri);
if (isHeader) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
// Don't offer tasks if the active file's extension is not a recognized C/C++ extension.
const fileIsCpp: boolean = util.isCppFile(editor.document.uri);
const fileIsC: boolean = util.isCFile(editor.document.uri);
if (!(fileIsCpp || fileIsC)) {
DebugConfigurationProvider.detectedBuildTasks = emptyTasks;
return;
}
if (fileIsCpp) {
if (!DebugConfigurationProvider.detectedCppBuildTasks || DebugConfigurationProvider.detectedCppBuildTasks.length === 0) {
DebugConfigurationProvider.detectedCppBuildTasks = await cppBuildTaskProvider.getTasks(true);
}
DebugConfigurationProvider.detectedBuildTasks = DebugConfigurationProvider.detectedCppBuildTasks;
} else {
if (!DebugConfigurationProvider.detectedCBuildTasks || DebugConfigurationProvider.detectedCBuildTasks.length === 0) {
DebugConfigurationProvider.detectedCBuildTasks = await cppBuildTaskProvider.getTasks(true);
}
DebugConfigurationProvider.detectedBuildTasks = DebugConfigurationProvider.detectedCBuildTasks;
}
}
@@ -557,17 +624,17 @@ 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;
}
} else if (util.isObject(sourceFileMapTarget)) {
const newSourceFileMapTarget: {"editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
const newSourceFileMapTarget: { "editorPath": string; "useForBreakpoints": boolean } = sourceFileMapTarget;
newSourceFileMapTarget["editorPath"] = util.resolveVariables(sourceFileMapTarget["editorPath"], 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.editorPath", "Replacing {0} '{1}' with '{2}'.", "editorPath", sourceFileMapTarget, newSourceFileMapTarget["editorPath"]);
target = newSourceFileMapTarget;
}
@@ -763,7 +830,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
const selectedConfig: vscode.DebugConfiguration | undefined = await this.selectConfiguration(textEditor, false, true);
if (!selectedConfig) {
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "true", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "true", "succeeded": "true" });
return; // User canceled it.
}
@@ -780,7 +847,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
selectedConfig.debuggerEvent = undefined;
// Write debug configuration in launch.json file.
await this.writeDebugConfig(selectedConfig, isExistingConfig, folder);
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "false", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.addConfigGear, { "configSource": ConfigSource.workspaceFolder, "configMode": ConfigMode.launchConfig, "cancelled": "false", "succeeded": "true" });
}
public async buildAndRun(textEditor: vscode.TextEditor): Promise<void> {
@@ -792,7 +859,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
let folder: vscode.WorkspaceFolder | undefined = vscode.workspace.getWorkspaceFolder(textEditor.document.uri);
const selectedConfig: CppDebugConfiguration | undefined = await this.selectConfiguration(textEditor);
if (!selectedConfig) {
Telemetry.logDebuggerEvent(DebuggerEvent.playButton, { "debugType": debugModeOn ? DebugType.debug : DebugType.run, "configSource": ConfigSource.unknown, "cancelled": "true", "success": "true" });
Telemetry.logDebuggerEvent(DebuggerEvent.playButton, { "debugType": debugModeOn ? DebugType.debug : DebugType.run, "configSource": ConfigSource.unknown, "cancelled": "true", "succeeded": "true" });
return; // User canceled it.
}
@@ -806,7 +873,7 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
}
selectedConfig.debugType = debugModeOn ? DebugType.debug : DebugType.run;
// startDebugging will trigger a call to resolveDebugConfiguration.
await vscode.debug.startDebugging(folder, selectedConfig, {noDebug: !debugModeOn});
await vscode.debug.startDebugging(folder, selectedConfig, { noDebug: !debugModeOn });
}
private async selectConfiguration(textEditor: vscode.TextEditor, pickDefault: boolean = true, onlyWorkspaceFolder: boolean = false): Promise<CppDebugConfiguration | undefined> {
@@ -870,10 +937,120 @@ export class DebugConfigurationProvider implements vscode.DebugConfigurationProv
if (e && e.message === util.failedToParseJson) {
vscode.window.showErrorMessage(util.failedToParseJson);
}
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "success": "false" });
Telemetry.logDebuggerEvent(config.debuggerEvent || DebuggerEvent.debugPanel, { "debugType": config.debugType || DebugType.debug, "configSource": config.configSource || ConfigSource.unknown, "configMode": configMode, "cancelled": "false", "succeeded": "false" });
}
}
}
private async expand(config: vscode.DebugConfiguration, folder: vscode.WorkspaceFolder | undefined): Promise<void> {
const folderPath: string | undefined = folder?.uri.fsPath || vscode.workspace.workspaceFolders?.[0].uri.fsPath;
const vars: ExpansionVars = config.variables ? config.variables : {};
vars.workspaceFolder = folderPath || '{workspaceFolder}';
vars.workspaceFolderBasename = folderPath ? path.basename(folderPath) : '{workspaceFolderBasename}';
const expansionOptions: ExpansionOptions = { vars, recursive: true };
return expandAllStrings(config, expansionOptions);
}
// Returns true when ALL steps succeed; stop all subsequent steps if one fails
private async deploySteps(config: vscode.DebugConfiguration, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
let succeeded: boolean = true;
const deployStart: number = new Date().getTime();
for (const step of config.deploySteps) {
succeeded = await this.singleDeployStep(config, step, cancellationToken);
if (!succeeded) {
break;
}
}
const deployEnd: number = new Date().getTime();
const telemetryProperties: { [key: string]: string } = {
Succeeded: `${succeeded}`,
IsDebugging: `${!config.noDebug || false}`
};
const telemetryMetrics: { [key: string]: number } = {
NumSteps: config.deploySteps.length,
Duration: deployEnd - deployStart
};
Telemetry.logDebuggerEvent('deploy', telemetryProperties, telemetryMetrics);
return succeeded;
}
private async singleDeployStep(config: vscode.DebugConfiguration, step: any, cancellationToken?: vscode.CancellationToken): Promise<boolean> {
if ((config.noDebug && step.debug === true) || (!config.noDebug && step.debug === false)) {
// Skip steps that doesn't match current launch mode. Explicit true/false check, since a step is always run when debug is undefined.
return true;
}
switch (step.type) {
case StepType.command: {
// VS Code commands are the same regardless of which extension invokes them, so just invoke them here.
if (step.args && !Array.isArray(step.args)) {
logger.getOutputChannelLogger().showErrorMessage(localize('command.args.must.be.array', '"args" in command deploy step must be an array.'));
return false;
}
const returnCode: unknown = await vscode.commands.executeCommand(step.command, ...step.args);
return !returnCode;
}
case StepType.scp: {
if (!step.files || !step.targetDir || !step.host) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.scp', '"host", "files", and "targetDir" are required in scp steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
let files: vscode.Uri[] = [];
if (util.isString(step.files)) {
files = files.concat((await globAsync(step.files)).map(file => vscode.Uri.file(file)));
} else if (util.isArrayOfString(step.files)) {
for (const fileGlob of (step.files as string[])) {
files = files.concat((await globAsync(fileGlob)).map(file => vscode.Uri.file(file)));
}
} else {
logger.getOutputChannelLogger().showErrorMessage(localize('incorrect.files.type.scp', '"files" must be a string or an array of strings in scp steps.'));
return false;
}
const scpResult: util.ProcessReturnType = await scp(files, host, step.targetDir, config.scpPath, jumpHosts, cancellationToken);
if (!scpResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.ssh: {
if (!step.host || !step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.ssh', '"host" and "command" are required for ssh steps.'));
return false;
}
const host: util.ISshHostInfo = { hostName: step.host.hostName, user: step.host.user, port: step.host.port };
const jumpHosts: util.ISshHostInfo[] = step.host.jumpHosts;
const localForwards: util.ISshLocalForwardInfo[] = step.host.localForwards;
const continueOn: string = step.continueOn;
const sshResult: util.ProcessReturnType = await ssh(host, step.command, config.sshPath, jumpHosts, localForwards, continueOn, cancellationToken);
if (!sshResult.succeeded || cancellationToken?.isCancellationRequested) {
return false;
}
break;
}
case StepType.shell: {
if (!step.command) {
logger.getOutputChannelLogger().showErrorMessage(localize('missing.properties.shell', '"command" is required for shell steps.'));
return false;
}
const taskResult: util.ProcessReturnType = await util.spawnChildProcess(step.command, undefined, step.continueOn);
if (!taskResult.succeeded || cancellationToken?.isCancellationRequested) {
logger.getOutputChannelLogger().showErrorMessage(taskResult.output);
return false;
}
break;
}
default: {
logger.getOutputChannelLogger().appendLine(localize('deploy.step.type.not.supported', 'Deploy step type {0} is not supported.', step.type));
return false;
}
}
return true;
}
}
export interface IConfigurationAssetProvider {
@@ -1026,7 +1203,7 @@ export class ConfigurationSnippetProvider implements vscode.CompletionItemProvid
items = [];
// Make a copy of each snippet since we are adding a comma to the end of the insertText.
this.snippets.forEach((item) => items.push({...item}));
this.snippets.forEach((item) => items.push({ ...item }));
items.map((item) => {
item.insertText = item.insertText + ','; // Add comma
@@ -4,14 +4,12 @@
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { Position, Range, RequestType, TextEdit } from 'vscode-languageclient';
import * as util from '../../common';
import { DefaultClient } from '../client';
import { CodeActionCodeInfo, CodeActionDiagnosticInfo, codeAnalysisFileToCodeActions, codeAnalysisCodeToFixes,
codeAnalysisAllFixes } from '../codeAnalysis';
import { makeVscodeRange } from '../utils';
import { CppSettings } from '../settings';
type LocalizeStringParams = util.LocalizeStringParams;
import { getLocalizedString, LocalizeStringParams } from '../localization';
interface GetCodeActionsRequestParams {
uri: string;
@@ -63,7 +61,7 @@ export class CodeActionProvider implements vscode.CodeActionProvider {
// Convert to vscode.CodeAction array
commands.forEach((command) => {
const title: string = util.getLocalizedString(command.localizeStringParams);
const title: string = getLocalizedString(command.localizeStringParams);
let wsEdit: vscode.WorkspaceEdit | undefined;
let codeActionKind: vscode.CodeActionKind = vscode.CodeActionKind.QuickFix;
if (command.edit) {
@@ -4,9 +4,9 @@
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { DefaultClient, LocalizeDocumentSymbol, GetDocumentSymbolRequestParams, GetDocumentSymbolRequest, SymbolScope } from '../client';
import * as util from '../../common';
import { processDelayedDidOpen } from '../extension';
import { makeVscodeRange } from '../utils';
import { getLocalizedString, getLocalizedSymbolScope } from '../localization';
export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
private client: DefaultClient;
@@ -17,18 +17,18 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
const documentSymbols: vscode.DocumentSymbol[] = [];
if (symbols) {
symbols.forEach((symbol) => {
let detail: string = util.getLocalizedString(symbol.detail);
let detail: string = getLocalizedString(symbol.detail);
if (symbol.scope === SymbolScope.Private) {
if (detail.length === 0) {
detail = "private";
} else {
detail = util.getLocalizedSymbolScope("private", detail);
detail = getLocalizedSymbolScope("private", detail);
}
} else if (symbol.scope === SymbolScope.Protected) {
if (detail.length === 0) {
detail = "protected";
} else {
detail = util.getLocalizedSymbolScope("protected", detail);
detail = getLocalizedSymbolScope("protected", detail);
}
}
@@ -22,6 +22,9 @@ interface CppInlayHint {
inlayHintKind: InlayHintKind;
isValueRef: boolean;
hasParamName: boolean;
leftPadding: boolean;
rightPadding: boolean;
identifierLength: number;
}
interface GetInlayHintsResult {
@@ -101,10 +104,22 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
let paramHintLabel: string = "";
if (settings.inlayHintsParameterNames) {
paramHintLabel = (settings.inlayHintsParameterNamesSuppressName && hint.hasParamName) ? "" : hint.label;
if (paramHintLabel !== "" && settings.inlayHintsParameterNamesHideLeadingUnderscores) {
let nonUnderscoreIndex: number = 0;
for (let i: number = 0; i < paramHintLabel.length; ++i) {
if (paramHintLabel[i] !== '_') {
nonUnderscoreIndex = i;
break;
}
}
if (nonUnderscoreIndex > 0) {
paramHintLabel = paramHintLabel.substring(nonUnderscoreIndex);
}
}
}
let refOperatorString: string = "";
if (settings.inlayHintsReferenceOperator && hint.isValueRef) {
refOperatorString = (paramHintLabel.length > 0) ? "& " : "&";
refOperatorString = (paramHintLabel.length > 0 && settings.inlayHintsReferenceOperatorShowSpace) ? "& " : "&";
}
let label: string = "";
if (paramHintLabel.length > 0 || refOperatorString.length > 0) {
@@ -123,13 +138,17 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
private createCacheEntry(inlayHintsResults: GetInlayHintsResult): InlayHintsCacheEntry {
const typeHints: vscode.InlayHint[] = [];
const settings: CppSettings = new CppSettings();
for (const h of inlayHintsResults.inlayHints) {
if (h.inlayHintKind === InlayHintKind.Type) {
const showOnLeft: boolean = settings.inlayHintsAutoDeclarationTypesShowOnLeft && h.identifierLength > 0;
const inlayHint: vscode.InlayHint = new vscode.InlayHint(
new vscode.Position(h.position.line, h.position.character),
h.label,
new vscode.Position(h.position.line, h.position.character +
(showOnLeft ? 0 : h.identifierLength)),
(showOnLeft ? h.label : ": " + h.label),
vscode.InlayHintKind.Type);
inlayHint.paddingRight = true;
inlayHint.paddingRight = showOnLeft || h.rightPadding;
inlayHint.paddingLeft = showOnLeft && h.leftPadding;
typeHints.push(inlayHint);
}
}
@@ -5,7 +5,7 @@
import * as vscode from 'vscode';
import { DefaultClient, GetSymbolInfoRequest, WorkspaceSymbolParams, LocalizeSymbolInformation, SymbolScope } from '../client';
import { makeVscodeLocation } from '../utils';
import * as util from '../../common';
import { getLocalizedString, getLocalizedSymbolScope } from '../localization';
export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
private client: DefaultClient;
@@ -23,13 +23,13 @@ export class WorkspaceSymbolProvider implements vscode.WorkspaceSymbolProvider {
// Convert to vscode.Command array
symbols.forEach((symbol) => {
let suffix: string = util.getLocalizedString(symbol.suffix);
let suffix: string = getLocalizedString(symbol.suffix);
let name: string = symbol.name;
if (suffix.length) {
if (symbol.scope === SymbolScope.Private) {
suffix = util.getLocalizedSymbolScope("private", suffix);
suffix = getLocalizedSymbolScope("private", suffix);
} else if (symbol.scope === SymbolScope.Protected) {
suffix = util.getLocalizedSymbolScope("protected", suffix);
suffix = getLocalizedSymbolScope("protected", suffix);
}
name = name + ' (' + suffix + ')';
} else {
+13 -66
View File
@@ -24,7 +24,7 @@ import { InlayHintsProvider } from './Providers/inlayHintProvider';
import { LanguageClient, LanguageClientOptions, ServerOptions, NotificationType, TextDocumentIdentifier, RequestType, ErrorAction, CloseAction, DidOpenTextDocumentParams, Range, Position, DocumentFilter } from 'vscode-languageclient';
import { SourceFileConfigurationItem, WorkspaceBrowseConfiguration, SourceFileConfiguration, Version } from 'vscode-cpptools';
import { Status, IntelliSenseStatus } from 'vscode-cpptools/out/testApi';
import { getLocalizedString, LocalizeStringParams } from './localization';
import { getLocaleId, getLocalizedString, LocalizeStringParams } from './localization';
import { Location, TextEdit } from './commonTypes';
import { makeVscodeRange, makeVscodeLocation } from './utils';
import * as util from '../common';
@@ -37,7 +37,6 @@ import { ClientCollection } from './clientCollection';
import { createProtocolFilter } from './protocolFilter';
import { DataBinding } from './dataBinding';
import minimatch = require("minimatch");
import * as logger from '../logger';
import { updateLanguageConfigurations, CppSourceStr } from './extension';
import { SettingsTracker, getTracker } from './settingsTracker';
import { getTestHook, TestHook } from '../testHook';
@@ -49,6 +48,7 @@ import * as nls from 'vscode-nls';
import { lookupString, localizedStringCount } from '../nativeStrings';
import { CodeAnalysisDiagnosticIdentifiersAndUri, RegisterCodeAnalysisNotifications, removeAllCodeAnalysisProblems,
removeCodeAnalysisProblems, RemoveCodeAnalysisProblemsParams } from './codeAnalysis';
import { DebugProtocolParams, getDiagnosticsChannel, getOutputChannelLogger, logDebugProtocol, Logger, logLocalized, showWarning, ShowWarningParams } from '../logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -64,10 +64,6 @@ const languageClientCrashTimes: number[] = [];
let clientCollection: ClientCollection;
let pendingTask: util.BlockingTask<any> | undefined;
let compilerDefaults: configs.CompilerDefaults;
let diagnosticsChannel: vscode.OutputChannel;
let outputChannel: vscode.OutputChannel;
let debugChannel: vscode.OutputChannel;
let warningChannel: vscode.OutputChannel;
let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection;
let workspaceDisposables: vscode.Disposable[] = [];
@@ -91,32 +87,10 @@ function logTelemetry(notificationBody: TelemetryPayload): void {
function setupOutputHandlers(): void {
console.assert(languageClient !== undefined, "This method must not be called until this.languageClient is set in \"onReady\"");
languageClient.onNotification(DebugProtocolNotification, (output) => {
if (!debugChannel) {
debugChannel = vscode.window.createOutputChannel(`${localize("c.cpp.debug.protocol", "C/C++ Debug Protocol")}`);
workspaceDisposables.push(debugChannel);
}
debugChannel.appendLine("");
debugChannel.appendLine("************************************************************************************************************************");
debugChannel.append(`${output}`);
});
languageClient.onNotification(DebugProtocolNotification, logDebugProtocol);
languageClient.onNotification(DebugLogNotification, logLocalized);
}
function log(output: string): void {
if (!outputChannel) {
outputChannel = logger.getOutputChannel();
workspaceDisposables.push(outputChannel);
}
outputChannel.appendLine(`${output}`);
}
function logLocalized(params: LocalizeStringParams): void {
const output: string = getLocalizedString(params);
log(output);
}
/** Note: We should not await on the following functions,
* or any funstion that returns a promise acquired from them,
* vscode.window.showInformationMessage, vscode.window.showWarningMessage, vscode.window.showErrorMessage
@@ -139,21 +113,6 @@ function showMessageWindow(params: ShowMessageWindowParams): void {
}
}
function showWarning(params: ShowWarningParams): void {
const message: string = getLocalizedString(params.localizeStringParams);
let showChannel: boolean = false;
if (!warningChannel) {
warningChannel = vscode.window.createOutputChannel(`${localize("c.cpp.warnings", "C/C++ Configuration Warnings")}`);
workspaceDisposables.push(warningChannel);
showChannel = true;
}
// Append before showing the channel, to avoid a delay.
warningChannel.appendLine(`[${new Date().toLocaleString()}] ${message}`);
if (showChannel) {
warningChannel.show(true);
}
}
function publishIntelliSenseDiagnostics(params: PublishIntelliSenseDiagnosticsParams): void {
if (!diagnosticsCollectionIntelliSense) {
diagnosticsCollectionIntelliSense = vscode.languages.createDiagnosticCollection(CppSourceStr);
@@ -192,12 +151,6 @@ interface TelemetryPayload {
metrics?: { [key: string]: number };
}
interface DebugProtocolParams {
jsonrpc: string;
method: string;
params?: any;
}
interface ReportStatusNotificationBody extends WorkspaceFolderParams {
status: string;
}
@@ -301,10 +254,6 @@ interface ShowMessageWindowParams {
localizeStringParams: LocalizeStringParams;
}
interface ShowWarningParams {
localizeStringParams: LocalizeStringParams;
}
export interface GetDocumentSymbolRequestParams {
uri: string;
}
@@ -1378,7 +1327,7 @@ export class DefaultClient implements Client {
},
vcpkg_root: util.getVcpkgRoot(),
experimentalFeatures: workspaceSettings.experimentalFeatures,
edgeMessagesDirectory: path.join(util.getExtensionFilePath("bin"), "messages", util.getLocaleId()),
edgeMessagesDirectory: path.join(util.getExtensionFilePath("bin"), "messages", getLocaleId()),
localizedStrings: localizedStrings,
packageVersion: util.packageJson.version,
legacyCompilerArgsBehavior: settings_legacyCompilerArgsBehavior
@@ -1518,7 +1467,7 @@ export class DefaultClient implements Client {
this.loggingLevel = newLoggingLevel;
const newLoggingLevelLogged: boolean = !!newLoggingLevel && newLoggingLevel !== "None" && newLoggingLevel !== "Error";
if (oldLoggingLevelLogged || newLoggingLevelLogged) {
const out: logger.Logger = logger.getOutputChannelLogger();
const out: Logger = getOutputChannelLogger();
out.appendLine(localize({ key: "loggingLevel.changed", comment: ["{0} is the setting name 'loggingLevel', {1} is a string value such as 'Debug'"] }, "{0} has changed to: {1}", "loggingLevel", changedSettings["loggingLevel"]));
}
}
@@ -1810,12 +1759,8 @@ export class DefaultClient implements Client {
public async logDiagnostics(): Promise<void> {
const response: GetDiagnosticsResult = await this.requestWhenReady(() => this.languageClient.sendRequest(GetDiagnosticsRequest, null));
if (!diagnosticsChannel) {
diagnosticsChannel = vscode.window.createOutputChannel(localize("c.cpp.diagnostics", "C/C++ Diagnostics"));
workspaceDisposables.push(diagnosticsChannel);
} else {
diagnosticsChannel.clear();
}
const diagnosticsChannel: vscode.OutputChannel = getDiagnosticsChannel();
diagnosticsChannel.clear();
const header: string = `-------- Diagnostics - ${new Date().toLocaleString()}\n`;
const version: string = `Version: ${util.packageJson.version}\n`;
@@ -2352,7 +2297,7 @@ export class DefaultClient implements Client {
} else if (message.endsWith("IntelliSense done")) {
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Debug") {
const out: logger.Logger = logger.getOutputChannelLogger();
const out: Logger = getOutputChannelLogger();
const duration: number = Date.now() - timeStamp;
out.appendLine(localize("update.intellisense.time", "Update IntelliSense time (sec): {0}", duration / 1000));
}
@@ -2425,7 +2370,7 @@ export class DefaultClient implements Client {
}
private updateTagParseStatus(notificationBody: LocalizeStringParams): void {
this.model.parsingWorkspaceStatus.Value = util.getLocalizedString(notificationBody);
this.model.parsingWorkspaceStatus.Value = getLocalizedString(notificationBody);
if (notificationBody.text.startsWith("Workspace parsing paused")) {
this.model.isParsingWorkspacePausable.Value = true;
this.model.isParsingWorkspacePaused.Value = true;
@@ -2768,7 +2713,7 @@ export class DefaultClient implements Client {
}
const settings: CppSettings = new CppSettings();
const out: logger.Logger = logger.getOutputChannelLogger();
const out: Logger = getOutputChannelLogger();
if (settings.loggingLevel === "Debug") {
out.appendLine(localize("configurations.received", "Custom configurations received:"));
}
@@ -2793,6 +2738,7 @@ export class DefaultClient implements Client {
itemConfig.compilerPath = compilerPathAndArgs.compilerPath;
if (providerVersion < Version.v6) {
itemConfig.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs;
itemConfig.compilerArgs = undefined;
} else {
itemConfig.compilerArgs = compilerPathAndArgs.allCompilerArgs;
}
@@ -2871,7 +2817,7 @@ export class DefaultClient implements Client {
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Debug") {
const out: logger.Logger = logger.getOutputChannelLogger();
const out: Logger = getOutputChannelLogger();
out.appendLine(localize("browse.configuration.received", "Custom browse configuration received: {0}", JSON.stringify(sanitized, null, 2)));
}
@@ -2884,6 +2830,7 @@ export class DefaultClient implements Client {
sanitized.compilerPath = compilerPathAndArgs.compilerPath;
if (providerVersion < Version.v6) {
sanitized.compilerArgsLegacy = compilerPathAndArgs.allCompilerArgs;
sanitized.compilerArgs = undefined;
} else {
sanitized.compilerArgs = compilerPathAndArgs.allCompilerArgs;
}
@@ -295,7 +295,6 @@ export class ClientCollection {
// this.defaultClient is already in this.languageClients, so do not call dispose() on it.
this.languageClients.forEach(client => client.dispose());
this.languageClients.clear();
cpptools.disposeWorkspaceData();
return cpptools.DefaultClient.stopLanguageClient();
}
}
+1 -1
View File
@@ -278,9 +278,9 @@ export function publishCodeAnalysisDiagnostics(params: PublishCodeAnalysisDiagno
const relatedCodeActions: CodeActionDiagnosticInfo[] = [];
const rootAndRelatedWorkspaceEdits: CodeActionWorkspaceEdit[] = [];
const rootAndRelatedIdentifiersAndUris: CodeAnalysisDiagnosticIdentifiersAndUri[] = [];
rootAndRelatedIdentifiersAndUris.push(identifiersAndUri);
if (workspaceEdit.workspaceEdit !== undefined) {
rootAndRelatedWorkspaceEdits.push(workspaceEdit);
rootAndRelatedIdentifiersAndUris.push(identifiersAndUri);
}
if (d.relatedInformation) {
diagnostic.relatedInformation = [];
@@ -122,10 +122,19 @@ export class CppBuildTaskProvider implements TaskProvider {
const knownCompilerPathsSet: Set<string> = new Set();
let knownCompilers: configs.KnownCompiler[] | undefined = await activeClient.getKnownCompilers();
if (knownCompilers) {
const compiler_condition: (info: configs.KnownCompiler) => boolean = info => ((fileIsCpp && !info.isC) || (fileIsC && info.isC)) &&
(!isCompilerValid || (!!userCompilerPathAndArgs &&
(path.basename(info.path) !== userCompilerPathAndArgs.compilerName))) &&
(!isWindows || !info.path.startsWith("/")); // TODO: Add WSL compiler support.
const compiler_condition: (info: configs.KnownCompiler) => boolean = info =>
(
// Filter out c compilers for cpp files and vice versa, except for cl.exe, which handles both.
path.basename(info.path) === "cl.exe" ||
(fileIsCpp && !info.isC) || (fileIsC && info.isC)
) &&
(
!isCompilerValid || (!!userCompilerPathAndArgs &&
(path.basename(info.path) !== userCompilerPathAndArgs.compilerName))
) &&
(
!isWindows || !info.path.startsWith("/")
); // TODO: Add WSL compiler support.
const cl_to_add: configs.KnownCompiler | undefined = userCompilerIsCl ? undefined : knownCompilers.find(info =>
((path.basename(info.path) === "cl.exe") && compiler_condition(info)));
knownCompilers = knownCompilers.filter(info =>
@@ -4,7 +4,14 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import { getExtensionFilePath } from '../common';
import { lookupString } from '../nativeStrings';
import * as nls from 'vscode-nls';
import path = require('path');
import * as fs from 'fs';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export interface LocalizeStringParams {
text: string;
@@ -24,3 +31,45 @@ export function getLocalizedString(params: LocalizeStringParams): string {
}
return indent + text;
}
interface VSCodeNlsConfig {
locale: string;
availableLanguages: {
[pack: string]: string;
};
}
export function getLocaleId(): string {
// This replicates the language detection used by initializeSettings() in vscode-nls
if (typeof process.env.VSCODE_NLS_CONFIG === 'string') {
const vscodeOptions: VSCodeNlsConfig = JSON.parse(process.env.VSCODE_NLS_CONFIG) as VSCodeNlsConfig;
if (vscodeOptions.availableLanguages) {
const value: any = vscodeOptions.availableLanguages['*'];
if (typeof value === 'string') {
return value;
}
}
if (typeof vscodeOptions.locale === 'string') {
return vscodeOptions.locale.toLowerCase();
}
}
return "en";
}
export function getLocalizedHtmlPath(originalPath: string): string {
const locale: string = getLocaleId();
if (!locale.startsWith("en")) {
const localizedFilePath: string = getExtensionFilePath(path.join("dist/html/", locale, originalPath));
if (fs.existsSync(localizedFilePath)) {
return localizedFilePath;
}
}
return getExtensionFilePath(originalPath);
}
export function getLocalizedSymbolScope(scope: string, detail: string): string {
return localize({
key: "c.cpp.symbolscope.separator", comment:
["{0} is an untranslated C++ keyword (e.g. \"private\") and {1} is either another keyword (e.g. \"typedef\") or a localized property (e.g. a localized version of \"declaration\""]
}, "{0}, {1}", scope, detail);
}
+12
View File
@@ -256,6 +256,10 @@ export class CppSettings extends Settings {
return super.Section.get<boolean>("inlayHints.autoDeclarationTypes.enabled") === true;
}
public get inlayHintsAutoDeclarationTypesShowOnLeft(): boolean {
return super.Section.get<boolean>("inlayHints.autoDeclarationTypes.showOnLeft") === true;
}
public get inlayHintsParameterNames(): boolean {
return super.Section.get<boolean>("inlayHints.parameterNames.enabled") === true;
}
@@ -264,10 +268,18 @@ export class CppSettings extends Settings {
return super.Section.get<boolean>("inlayHints.parameterNames.suppressWhenArgumentContainsName") === true;
}
public get inlayHintsParameterNamesHideLeadingUnderscores(): boolean {
return super.Section.get<boolean>("inlayHints.parameterNames.hideLeadingUnderscores") === true;
}
public get inlayHintsReferenceOperator(): boolean {
return super.Section.get<boolean>("inlayHints.referenceOperator.enabled") === true;
}
public get inlayHintsReferenceOperatorShowSpace(): boolean {
return super.Section.get<boolean>("inlayHints.referenceOperator.showSpace") === true;
}
public get enhancedColorization(): boolean {
return super.Section.get<string>("enhancedColorization") === "Enabled"
&& super.Section.get<string>("intelliSenseEngine") === "Default"
@@ -10,6 +10,7 @@ import * as vscode from 'vscode';
import * as util from '../common';
import * as config from './configurations';
import * as telemetry from '../telemetry';
import { getLocalizedHtmlPath } from './localization';
// TODO: share ElementId between SettingsPanel and SettingsApp. Investigate why SettingsApp cannot import/export
const elementId: { [key: string]: string } = {
@@ -373,7 +374,7 @@ export class SettingsPanel {
private getHtml(): string {
let content: string | undefined;
content = fs.readFileSync(util.getLocalizedHtmlPath("ui/settings.html")).toString();
content = fs.readFileSync(getLocalizedHtmlPath("ui/settings.html")).toString();
if (this.panel && this.panel.webview) {
const cppImageUri: vscode.Uri = this.panel.webview.asWebviewUri(vscode.Uri.file(path.join(util.extensionPath, 'LanguageCCPP_color_128x.png')));
+340
View File
@@ -0,0 +1,340 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import { stripEscapeSequences, isWindows, escapeStringForRegex } from '../common';
export type IDifferingHostConfirmationProvider =
(message: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export type IFingerprintConfirmationProvider =
(host: string, fingerprint: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export interface IInteraction {
canceled?: boolean;
postAction?: 'consume' | 'keep';
response?: string;
isPassword?: boolean;
continue?: boolean; // Continue without waiting for the program to finish or pause
}
export interface IInteractorDataDetails {
detectedServerKey?: string;
detail?: string;
}
export interface IInteractor {
id: string;
onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction>;
}
export class MitmInteractor implements IInteractor {
static ID = 'mitm';
constructor() { }
get id(): string {
return MitmInteractor.ID;
}
async onData(data: string): Promise<IInteraction> {
if (!!data.match('Port forwarding is disabled to avoid man-in-the-middle attacks.')) {
throw Error('Port forwarding is disabled to avoid man-in-the-middle attacks.');
}
return {};
}
}
export class FingerprintInteractor implements IInteractor {
static ID = 'fingerprint';
constructor(private readonly hostName: string, private readonly confirmationProvider: IFingerprintConfirmationProvider) { }
get id(): string {
return FingerprintInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const fingerprintMatcher: RegExp = /fingerprint\sis\s(.+)\./;
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
let fingerprintMatch: RegExpMatchArray | null;
if (
data.includes('Are you sure you want to continue connecting') &&
(fingerprintMatch = data.match(fingerprintMatcher))
) {
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(
this.hostName,
fingerprintMatch[1],
cancelToken
);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
} else if (
isWindows() &&
(data.includes('The authenticity of host ') || (data === '' && extraDetails?.detectedServerKey))
) {
// hack for #1195
// First line local server case (git ssh only gives the first line over ssh_askpass)
const key: string = extraDetails?.detectedServerKey || '(unknown)';
result.postAction = 'consume';
const confirmation: string | undefined = await this.confirmationProvider(this.hostName, key, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export class DifferingHostKeyInteractor implements IInteractor {
static ID = 'differing host key';
constructor(private readonly confirmationProvider: IDifferingHostConfirmationProvider) { }
get id(): string {
return DifferingHostKeyInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, _extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
data = data.trim();
if (
data.includes('Are you sure you want to continue connecting') &&
data.includes('Offending key for IP in') &&
data.includes('Matching host key in')
) {
result.postAction = 'consume';
const message: string = data.substring(data.indexOf('Warning'), data.indexOf('Are')).trim();
const confirmation: string | undefined = await this.confirmationProvider(message, cancelToken);
if (confirmation) {
result.response = confirmation;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IStringProvider =
(key?: string, detail?: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class PassphraseInteractor implements IInteractor {
static ID = 'passphrase';
constructor(private readonly passphraseProvider: IStringProvider) { }
get id(): string {
return PassphraseInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const lines: string[] = data.trim().split('\n');
if (lines.some(l => l.indexOf('Enter passphrase for') >= 0)) {
result.postAction = 'consume';
const passphrase: string | undefined = await this.passphraseProvider(undefined, undefined, cancelToken); // TODO keep track of the key name
if (typeof passphrase === 'string') {
result.response = passphrase;
result.isPassword = true;
} else {
result.canceled = true;
}
} else if (lines.some(l => l.indexOf('Identity added:') >= 0)) {
result.postAction = 'consume';
}
return result;
}
}
export function getExitCode(output: string, marker: string): number | undefined {
const regex: RegExp = new RegExp(`${marker}##([0-9]*)##`);
const match: RegExpExecArray | null = regex.exec(output);
if (match) {
try {
const num: number = parseInt(match[1]);
return Number.isNaN(num) ? undefined : num;
} catch (err) {
return undefined;
}
}
return 0;
}
/**
* Matches SSH password prompt of format:
* 's password:
* or
* Password:
* not
* 's old password:
* 's new password:
*/
function getPasswordPrompt(data: string, details?: IInteractorDataDetails): { user?: string; message?: string } | undefined {
if (data.includes('Password:')) {
// Password prompt for unspecified user
return { user: '' };
}
// Got \r\r\n as a line ending here
const match: RegExpMatchArray | null = stripEscapeSequences(data).match(/([a-zA-Z0-9\-_@\.]*)'s password:/);
if (match) {
return {
user: match[1],
message: details ? details.detail : undefined
};
}
return undefined;
}
export class PasswordInteractor implements IInteractor {
static ID = 'password';
constructor(private readonly passwordProvider: IStringProvider) { }
get id(): string {
return PasswordInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken, extraDetails?: IInteractorDataDetails): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pwPrompt: { user?: string; message?: string } | undefined = getPasswordPrompt(data, extraDetails);
if (pwPrompt && typeof pwPrompt.user === 'string') {
result.postAction = 'consume';
const password: string | undefined = await this.passwordProvider(pwPrompt.user, pwPrompt.message, cancelToken);
if (typeof password === 'string') {
result.response = password;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export type IVerificationCodeProvider =
(msg: string, cancelToken?: vscode.CancellationToken) => Promise<string | undefined>;
export class TwoFacInteractor implements IInteractor {
static ID = '2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return TwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Verification code:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter verification code', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
// https://github.com/microsoft/vscode-remote-release/issues/2170
export class DuoTwoFacInteractor implements IInteractor {
static ID = 'duo-2fa';
constructor(private readonly verificationCodeProvider: IVerificationCodeProvider) { }
get id(): string {
return DuoTwoFacInteractor.ID;
}
async onData(data: string, cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
if (data.includes('Passcode:')) {
result.postAction = 'consume';
const verificationCode: string | undefined = await this.verificationCodeProvider('Enter passcode', cancelToken);
if (typeof verificationCode === 'string') {
result.response = verificationCode;
result.isPassword = true;
} else {
result.canceled = true;
}
}
return result;
}
}
export class ContinueOnInteractor implements IInteractor {
static ID = 'continueOn';
constructor(private readonly continueOn: string) { }
get id(): string {
return ContinueOnInteractor.ID;
}
async onData(data: string, _cancelToken?: vscode.CancellationToken): Promise<IInteraction> {
const result: IInteraction = { postAction: 'keep' };
const pattern: string = escapeStringForRegex(this.continueOn);
const re: RegExp = new RegExp(pattern, 'g');
if (data.match(re)) {
result.continue = true;
}
return result;
}
}
export class ComposedInteractor implements IInteractor {
constructor(private readonly interactors: IInteractor[]) { }
get id(): string {
return 'composed';
}
async onData(data: string): Promise<IInteraction> {
for (const interactor of this.interactors) {
const result: IInteraction = await interactor.onData(data);
if (result.postAction === 'consume') {
return result;
}
}
return { postAction: 'keep' };
}
}
export interface ISystemInteractor {
createTerminal(options: vscode.TerminalOptions): vscode.Terminal;
onDidCloseTerminal: typeof vscode.window.onDidCloseTerminal;
onDidWriteTerminalData: typeof vscode.window.onDidWriteTerminalData;
}
export const defaultSystemInteractor: ISystemInteractor = {
createTerminal: vscode.window.createTerminal,
onDidCloseTerminal: vscode.window.onDidCloseTerminal,
onDidWriteTerminalData: vscode.window.onDidWriteTerminalData
};
+98
View File
@@ -0,0 +1,98 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { ISshHostInfo, ISshLocalForwardInfo, ProcessReturnType } from '../common';
import { defaultSystemInteractor } from './commandInteractors';
import { runSshTerminalCommandWithLogin } from './sshCommandRunner';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export async function scp(files: vscode.Uri[], host: ISshHostInfo, targetDir: string, scpPath?: string, jumpHosts?: ISshHostInfo[], cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// upper case P
args.push('-P', `${host.port}`);
}
args.push(files.map(uri => `"${uri.fsPath}"`).join(' '), `${getFullHostAddressNoPort(host)}:${targetDir}`);
return runSshTerminalCommandWithLogin(host, { systemInteractor: defaultSystemInteractor, nickname: 'scp', command: `"${scpPath || 'scp'}" ${args.join(' ')}`, token: cancellationToken });
}
export function ssh(host: ISshHostInfo, command: string, sshPath?: string, jumpHosts?: ISshHostInfo[], localForwards?: ISshLocalForwardInfo[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const args: string[] = [];
if (jumpHosts && jumpHosts.length > 0) {
args.push('-J', jumpHosts.map(getFullHostAddress).join(','));
}
if (host.port) {
// lower case p
args.push('-p', `${host.port}`);
}
if (localForwards) {
localForwards.forEach(info => args.push(...localForwardToArgs(info)));
}
args.push(getFullHostAddressNoPort(host), `"${command}"`);
return runSshTerminalCommandWithLogin(host, {
systemInteractor: defaultSystemInteractor,
command: `"${sshPath || 'ssh'}" ${args.join(' ')}`,
nickname: 'ssh',
continueOn,
token: cancellationToken
});
}
/**
* Takes one local forward info and convert it to '-L' args in ssh.
*/
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'));
}
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'));
}
if (!localForward.remoteSocket && (!localForward.host || !localForward.hostPort)) {
throw Error(localize('local.forward.remote.missing', '"host" and "hostPort", or "remoteSocket" required in localForwards'));
}
let arg: string = '';
if (localForward.localSocket) {
arg += `${localForward.localSocket}:`;
}
if (localForward.bindAddress) {
arg += `${localForward.bindAddress}:`;
}
if (localForward.port) {
arg += `${localForward.port}:`;
}
if (localForward.remoteSocket) {
arg += `${localForward.remoteSocket}`;
}
if (localForward.host && localForward.hostPort) {
arg += `${localForward.host}:${localForward.hostPort}`;
}
return ['-L', arg];
}
/** user@host */
function getFullHostAddressNoPort(host: ISshHostInfo): string {
return host.user ? `${host.user}@${host.hostName}` : `${host.hostName}`;
}
function getFullHostAddress(host: ISshHostInfo): string {
const fullHostName: string = getFullHostAddressNoPort(host);
return host.port ? `${fullHostName}:${host.port}` : fullHostName;
}
+518
View File
@@ -0,0 +1,518 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as os from 'os';
import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import {
DifferingHostKeyInteractor,
DuoTwoFacInteractor,
FingerprintInteractor,
IInteractor,
MitmInteractor,
PassphraseInteractor,
PasswordInteractor,
TwoFacInteractor,
ContinueOnInteractor,
ISystemInteractor,
IInteraction
} from './commandInteractors';
import { isWindows, ISshHostInfo, splitLines, stripEscapeSequences, ProcessReturnType } from '../common';
import { getOutputChannelLogger } from '../logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export class CanceledError extends Error {
constructor() {
super(localize('ssh.canceled', 'SSH command canceled'));
}
}
export interface ICommandResult {
stdout: string;
stderr: string;
}
export function showPassphraseInputBox(
keyName?: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
const keyStr: string = keyName ? `"${keyName}"` : '';
const msg: string = localize('ssh.passphrase.input.box', 'Enter passphrase for ssh key {0}', keyStr);
return showInputBox(msg, prompt, cancelToken);
}
export function showPasswordInputBox(
user: string | undefined,
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');
return showInputBox(msg, prompt, cancelToken);
}
export function showVerificationCodeInputBox(
msg: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showInputBox(msg, undefined, cancelToken);
}
export async function showInputBox(
msg: string,
prompt?: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.InputBox = vscode.window.createInputBox();
quickPick.title = msg;
quickPick.prompt = prompt;
quickPick.password = true;
quickPick.ignoreFocusOut = true;
let isAccepted: boolean = false;
quickPick.onDidAccept(() => {
isAccepted = true;
const passphrase: string = quickPick.value;
quickPick.dispose();
resolve(passphrase);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
reject(new CanceledError());
quickPick.dispose();
});
}
});
}
class ConfirmationItem implements vscode.QuickPickItem, vscode.MessageItem {
title: string;
isCloseAffordance: boolean = true;
constructor(public label: string, public value: string) {
this.title = label;
}
}
const continueConfirmationPlaceholder: string = localize('ssh.continue.confirmation.placeholder', 'Are you sure you want to continue?');
export async function showHostKeyConfirmation(
host: string,
fingerprint: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(
localize('ssh.host.key.confirmation.title', '"{0}" has fingerprint "{1}".', host, fingerprint),
continueConfirmationPlaceholder,
cancelToken
);
}
export async function showDifferingHostConfirmation(
message: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return showConfirmationPicker(message, continueConfirmationPlaceholder, cancelToken);
}
async function showConfirmationPicker(
title: string,
placeholder: string,
cancelToken?: vscode.CancellationToken
): Promise<string | undefined> {
return new Promise((resolve, reject) => {
const quickPick: vscode.QuickPick<ConfirmationItem> = vscode.window.createQuickPick<ConfirmationItem>();
quickPick.canSelectMany = false;
quickPick.items = [new ConfirmationItem(localize('continue', 'Continue'), 'yes'), new ConfirmationItem(localize('cancel', 'Cancel'), 'no')];
quickPick.title = title;
quickPick.placeholder = placeholder;
let isAccepted: boolean = false;
quickPick.onDidAccept(async () => {
isAccepted = true;
const value: string = quickPick.selectedItems[0].value;
quickPick.dispose();
resolve(value);
});
quickPick.onDidHide(() => {
if (!isAccepted) {
resolve(undefined);
}
});
quickPick.show();
if (cancelToken) {
cancelToken.onCancellationRequested(() => {
quickPick.hide();
reject(new CanceledError());
});
}
});
}
export interface ITerminalCommandWithLoginArgs {
systemInteractor: ISystemInteractor;
command: string;
nickname: string;
marker?: string;
usedInteractors?: Set<string>;
interactor?: IInteractor;
cwd?: string;
token?: vscode.CancellationToken;
continueOn?: string;
revealTerminal?: vscode.Event<void>;
}
export async function runSshTerminalCommandWithLogin(
host: ISshHostInfo,
terminalArgs: ITerminalCommandWithLoginArgs,
showLoginTerminal = false
): Promise<ProcessReturnType> {
const interactors: IInteractor[] = [];
if (terminalArgs.interactor) {
interactors.push(terminalArgs.interactor);
}
if (!showLoginTerminal) {
interactors.push(
new MitmInteractor(),
new FingerprintInteractor(host.hostName, showHostKeyConfirmation),
new PassphraseInteractor(showPassphraseInputBox),
new DifferingHostKeyInteractor(showDifferingHostConfirmation),
new PasswordInteractor(showPasswordInputBox),
new TwoFacInteractor(showVerificationCodeInputBox),
new DuoTwoFacInteractor(showVerificationCodeInputBox)
);
}
if (terminalArgs.continueOn) {
interactors.push(new ContinueOnInteractor(terminalArgs.continueOn));
}
// This terminal is always local
const result: ProcessReturnType = await runInteractiveSshTerminalCommand({
systemInteractor: terminalArgs.systemInteractor,
command: terminalArgs.command,
interactors,
usedInteractors: terminalArgs.usedInteractors,
nickname: terminalArgs.nickname,
token: terminalArgs.token,
marker: terminalArgs.marker,
revealTerminal: terminalArgs.revealTerminal,
showLoginTerminal,
cwd: terminalArgs.cwd ? vscode.Uri.file(terminalArgs.cwd) : undefined
});
return result;
}
export interface ITerminalCommandArgs {
systemInteractor: ISystemInteractor;
command: string;
interactors?: IInteractor[];
nickname: string;
usedInteractors?: Set<string>;
sendText?: string;
cwd?: vscode.Uri;
terminalIsWindows?: boolean;
token?: vscode.CancellationToken;
marker?: string;
revealTerminal?: vscode.Event<void>;
showLoginTerminal?: boolean; // If true, respect the showLoginTerminal setting
}
export function getPauseLogMarker(uuid: string): string {
return `${uuid}: pauseLog`;
}
export function getResumeLogMarker(uuid: string): string {
return `${uuid}: resumeLog`;
}
export function runInteractiveSshTerminalCommand(args: ITerminalCommandArgs): Promise<ProcessReturnType> {
const disposables: vscode.Disposable[] = [];
const { systemInteractor, command, interactors, nickname, token } = args;
let logIsPaused: boolean = false;
return new Promise(async (resolve, reject) => {
let stdout: string = '';
let windowListener: vscode.Disposable | undefined;
let terminalListener: vscode.Disposable | undefined;
let terminal: vscode.Terminal | undefined;
let tokenListener: vscode.Disposable;
let continueWithoutExiting: boolean = false;
const clean = () => {
if (terminalListener) {
terminalListener.dispose();
terminalListener = undefined;
}
if (terminal) {
terminal.dispose();
terminal = undefined;
}
if (windowListener) {
windowListener.dispose();
windowListener = undefined;
}
if (tokenListener) {
tokenListener.dispose();
}
disposables.forEach(disposable => disposable.dispose());
};
const done = (cancel: boolean = false, noClean: boolean = false, exitCode?: number) => {
if (!noClean) {
clean();
}
getOutputChannelLogger().appendLine(cancel ? localize('ssh.terminal.command.canceled', '"{0}" terminal command canceled.', nickname) : localize('ssh.terminal.command.done', '"{0}" terminal command done.', nickname));
if (cancel) {
if (continueWithoutExiting) {
getOutputChannelLogger().showWarningMessage(localize('ssh.continuing.command.canceled', 'Task \'{0}\' is canceled, but the underlying command may not be terminated. Please check manually.', command));
}
return reject(new CanceledError());
}
// When using showLoginTerminal, stdout include the passphrase prompt, etc. Try to get just the command output on the last line.
const actualOutput: string | undefined = cancel ? '' : lastNonemptyLine(stdout);
resolve({ succeeded: !exitCode, exitCode, output: actualOutput || '' });
};
const failed = (error?: any) => {
clean();
getOutputChannelLogger().showErrorMessage(localize('ssh.process.failed', '"{0}" process failed: {1}', nickname, error));
reject(error);
};
const handleOutputLogging = (data: string): void => {
let nextPauseState: boolean | undefined;
if (args.marker) {
const pauseMarker: string = getPauseLogMarker(args.marker);
const pauseIdx: number = data.lastIndexOf(pauseMarker);
if (pauseIdx >= 0) {
data = data.substring(0, pauseIdx + pauseMarker.length);
nextPauseState = true;
}
const resumeIdx: number = data.lastIndexOf(getResumeLogMarker(args.marker));
if (resumeIdx >= 0) {
data = data.substring(resumeIdx);
nextPauseState = false;
}
}
// Log the chunk of data that includes the pause/resume markers,
// so unpause first and pause after logging
if (!logIsPaused) {
logReceivedData(data, nickname);
}
if (typeof nextPauseState === 'boolean') {
logIsPaused = nextPauseState;
}
};
const handleTerminalOutput = async (dataWrite: vscode.TerminalDataWriteEvent): Promise<void> => {
handleOutputLogging(dataWrite.data);
stdout += dataWrite.data;
if (interactors) {
for (const interactor of interactors) {
try {
const interaction: IInteraction = await interactor.onData(stdout);
if (interaction.postAction === 'consume') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
stdout = '';
}
if (interaction.canceled) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
done(true);
return;
}
if (interaction.continue) {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
continueWithoutExiting = true;
done(false, true);
return;
}
if (typeof interaction.response === 'string') {
if (args.usedInteractors) {
args.usedInteractors.add(interactor.id);
}
if (terminal) {
terminal.sendText(`${interaction.response}\n`);
const logOutput: string = interaction.isPassword
? interaction.response.replace(/./g, '*')
: interaction.response;
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, logOutput));
}
}
} catch (e) {
failed(e);
}
}
}
};
if (token) {
tokenListener = token.onCancellationRequested(() => {
done(true);
});
}
const terminalIsWindows: boolean = typeof args.terminalIsWindows === 'boolean' ? args.terminalIsWindows : isWindows();
try {
// the terminal process should not fail, but exit cleanly
let shellArgs: string | string[];
if (args.sendText) {
shellArgs = '';
} else {
shellArgs = terminalIsWindows ? `/c (${command})\nexit /b %ErrorLevel%` : ['-c', `${command}\nexit $?`];
}
const options: vscode.TerminalOptions = {
cwd:
args.cwd ||
(terminalIsWindows
? vscode.Uri.file(os.homedir() || 'c:\\')
: vscode.Uri.file(os.homedir() || '/')),
name: nickname,
shellPath: getShellPath(terminalIsWindows),
shellArgs,
hideFromUser: true
};
let terminalDataHandlingQueue: Promise<void> = Promise.resolve();
terminalListener = systemInteractor.onDidWriteTerminalData(async e => {
if (e.terminal !== terminal) {
return;
}
terminalDataHandlingQueue = terminalDataHandlingQueue.finally(() => handleTerminalOutput(e));
});
terminal = systemInteractor.createTerminal(options);
if (args.revealTerminal) {
disposables.push(
args.revealTerminal(() => {
if (terminal) {
terminal.show();
}
})
);
}
if (args.sendText) {
const sendText: string = terminalIsWindows ? `(${args.sendText})\nexit /b %ErrorLevel%` : `${args.sendText}\nexit $?`;
terminal.sendText(sendText);
getOutputChannelLogger().appendLine(localize('ssh.wrote.data.to.terminal', '"{0}" wrote data to terminal: "{1}".', nickname, args.sendText));
}
if (args.showLoginTerminal) {
terminal.show();
}
windowListener = systemInteractor.onDidCloseTerminal(t => {
if (t === terminal) {
terminal = undefined; // Is already disposed
done(false, false, t.exitStatus?.code);
}
});
} catch (error) {
failed(error);
}
});
}
function getShellPath(_isWindows: boolean): string {
if (_isWindows) {
// Some users don't have cmd.exe on the path...
if (process.env.SystemRoot) {
// This var should always exist but be paranoid
const cmdPath: string = path.join(process.env.SystemRoot, 'System32', 'cmd.exe');
return cmdPath;
} else {
return 'cmd.exe';
}
} else {
// Note - can't rely on having sh in path (#590), and can't check the disk (bc remote terminals)
return '/bin/sh';
}
}
function logReceivedData(data: string, nickname: string): void {
const logData: string = data.replace(/\r?\n$/, ''); // Trim single trailing newline for nicer log
if (logData === ' ') {
// From the sleep command that must periodically echo ' '
return;
}
const markedLines: string = logData
.split(/\n/)
.map(line => `${nickname}> ${line}`)
.join('\n');
getOutputChannelLogger().appendLine(markedLines);
}
function lastNonemptyLine(str: string): string | undefined {
const lines: string[] = splitLines(str);
if (isWindows()) {
let outputContainingPipeError: string = '';
for (let i: number = lines.length - 1; i >= 0; i--) {
const strippedLine: string = stripEscapeSequences(lines[i]);
if (strippedLine.match(/The process tried to write to a nonexistent pipe/)) {
outputContainingPipeError = strippedLine;
continue;
}
if (!!strippedLine) {
return strippedLine;
}
}
if (outputContainingPipeError) {
return outputContainingPipeError;
}
}
const nonEmptyLines: string[] = lines.filter(l => !!l);
return nonEmptyLines[nonEmptyLines.length - 1];
}
+115 -89
View File
@@ -17,11 +17,10 @@ import * as assert from 'assert';
import * as https from 'https';
import * as tmp from 'tmp';
import { ClientRequest, OutgoingHttpHeaders } from 'http';
import { lookupString } from './nativeStrings';
import * as nls from 'vscode-nls';
import { Readable } from 'stream';
import * as jsonc from 'comment-json';
import { TargetPopulation } from 'vscode-tas-client';
import { CppSettings } from './LanguageServer/settings';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -321,10 +320,13 @@ export function resolveCachePath(input: string | undefined, additionalEnvironmen
return resolvedPath;
}
export function isWindows(): boolean {
return os.platform() === 'win32';
}
export function defaultExePath(): string {
const isWindows: boolean = os.platform() === 'win32';
const exePath: string = path.join('${fileDirname}', '${fileBasenameNoExtension}');
return isWindows ? exePath + '.exe' : exePath;
return isWindows() ? exePath + '.exe' : exePath;
}
export function findExePathInArgs(args: string[]): string | undefined {
@@ -570,9 +572,9 @@ export function checkDirectoryExistsSync(dirPath: string): boolean {
}
/** Test whether a relative path exists */
export function checkPathExistsSync(path: string, relativePath: string, isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
export function checkPathExistsSync(path: string, relativePath: string, _isWindows: boolean, isWSL: boolean, isCompilerPath: boolean): { pathExists: boolean; path: string } {
let pathExists: boolean = true;
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && isWindows && !isWSL && fs.existsSync(path + ".exe");
const existsWithExeAdded: (path: string) => boolean = (path: string) => isCompilerPath && _isWindows && !isWSL && fs.existsSync(path + ".exe");
if (!fs.existsSync(path)) {
if (existsWithExeAdded(path)) {
path += ".exe";
@@ -711,32 +713,83 @@ export function execChildProcess(process: string, workingDirectory?: string, cha
});
}
export function spawnChildProcess(process: string, args: string[], workingDirectory: string,
dataCallback: (stdout: string) => void, errorCallback: (stderr: string) => void): Promise<void> {
export interface ProcessReturnType {
succeeded: boolean;
exitCode?: number | NodeJS.Signals;
output: string;
}
return new Promise<void>(function (resolve, reject): void {
const child: child_process.ChildProcess = child_process.spawn(process, args, { cwd: workingDirectory });
export async function spawnChildProcess(program: string, args: string[] = [], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessReturnType> {
const programOutput: ProcessOutput = await spawnChildProcessImpl(program, args, continueOn, cancellationToken);
const exitCode: number | NodeJS.Signals | undefined = programOutput.exitCode;
const settings: CppSettings = new CppSettings();
if (settings.loggingLevel === "Information" || settings.loggingLevel === "Debug") {
getOutputChannelLogger().appendLine(`$ ${program} ${args.join(' ')}\n${programOutput.stderr || programOutput.stdout}\n`);
}
if (programOutput.exitCode) {
return { succeeded: false, exitCode, output: programOutput.stderr || programOutput.stdout || localize('process.exited', 'Process exited with code {0}', exitCode) };
} else {
let stdout: string;
if (programOutput.stdout.length) {
// Type system doesn't work very well here, so we need call toString
stdout = programOutput.stdout;
} else {
stdout = localize('process.succeeded', 'Process executed successfully.');
}
return { succeeded: true, exitCode, output: stdout };
}
}
const stdout: Readable | null = child.stdout;
if (stdout) {
stdout.on('data', (data) => {
dataCallback(`${data}`);
});
interface ProcessOutput {
exitCode?: number | NodeJS.Signals;
stdout: string;
stderr: string;
}
async function spawnChildProcessImpl(program: string, args: string[], continueOn?: string, cancellationToken?: vscode.CancellationToken): Promise<ProcessOutput> {
return new Promise(async (resolve, reject) => {
let proc: child_process.ChildProcess;
if (await isExecutable(program)) {
proc = child_process.spawn(`.${isWindows() ? '\\' : '/'}${path.basename(program)}`, args, { shell: true, cwd: path.dirname(program) });
} else {
proc = child_process.spawn(program, args, { shell: true });
}
const stderr: Readable | null = child.stderr;
if (stderr) {
stderr.on('data', (data) => {
errorCallback(`${data}`);
});
}
const cancellationTokenListener: vscode.Disposable | undefined = cancellationToken?.onCancellationRequested(() => {
getOutputChannelLogger().appendLine(localize('killing.process', 'Killing process {0}', program));
proc.kill();
});
child.on('exit', (code: number) => {
if (code !== 0) {
reject(new Error(localize("process.exited.with.code", "{0} exited with error code {1}", process, code)));
} else {
resolve();
const clean = () => {
proc.removeAllListeners();
if (cancellationTokenListener) {
cancellationTokenListener.dispose();
}
};
let stdout: string = '';
let stderr: string = '';
if (proc.stdout) {
proc.stdout.on('data', data => {
stdout += data.toString();
if (continueOn) {
const continueOnReg: string = escapeStringForRegex(continueOn);
if (stdout.search(continueOnReg)) {
resolve({ stdout: stdout.trim(), stderr: stderr.trim() });
}
}
});
}
if (proc.stderr) {
proc.stderr.on('data', data => stderr += data.toString());
}
proc.on('close', (code, signal) => {
clean();
resolve({ exitCode: code || signal, stdout: stdout.trim(), stderr: stderr.trim() });
});
proc.on('error', error => {
clean();
reject(error);
});
});
}
@@ -927,7 +980,6 @@ function resolveWindowsEnvironmentVariables(str: string): string {
}
function legacyExtractArgs(argsString: string): string[] {
const isWindows: boolean = os.platform() === 'win32';
const result: string[] = [];
let currentArg: string = "";
let isWithinDoubleQuote: boolean = false;
@@ -951,7 +1003,7 @@ function legacyExtractArgs(argsString: string): string[] {
}
} else if (c === '\'') {
// On Windows, a single quote string is not allowed to join multiple args into a single arg
if (!isWindows) {
if (!isWindows()) {
if (!isWithinDoubleQuote) {
isWithinSingleQuote = !isWithinSingleQuote;
}
@@ -1197,67 +1249,6 @@ export class BlockingTask<T> {
}
}
interface VSCodeNlsConfig {
locale: string;
availableLanguages: {
[pack: string]: string;
};
}
export function getLocaleId(): string {
// This replicates the language detection used by initializeSettings() in vscode-nls
if (isString(process.env.VSCODE_NLS_CONFIG)) {
const vscodeOptions: VSCodeNlsConfig = JSON.parse(process.env.VSCODE_NLS_CONFIG) as VSCodeNlsConfig;
if (vscodeOptions.availableLanguages) {
const value: any = vscodeOptions.availableLanguages['*'];
if (isString(value)) {
return value;
}
}
if (isString(vscodeOptions.locale)) {
return vscodeOptions.locale.toLowerCase();
}
}
return "en";
}
export function getLocalizedHtmlPath(originalPath: string): string {
const locale: string = getLocaleId();
if (!locale.startsWith("en")) {
const localizedFilePath: string = getExtensionFilePath(path.join("dist/html/", locale, originalPath));
if (fs.existsSync(localizedFilePath)) {
return localizedFilePath;
}
}
return getExtensionFilePath(originalPath);
}
export interface LocalizeStringParams {
text: string;
stringId: number;
stringArgs: string[];
indentSpaces: number;
}
export function getLocalizedString(params: LocalizeStringParams): string {
let indent: string = "";
if (params.indentSpaces) {
indent = " ".repeat(params.indentSpaces);
}
let text: string = params.text;
if (params.stringId !== 0) {
text = lookupString(params.stringId, params.stringArgs);
}
return indent + text;
}
export function getLocalizedSymbolScope(scope: string, detail: string): string {
return localize({
key: "c.cpp.symbolscope.separator", comment:
["{0} is an untranslated C++ keyword (e.g. \"private\") and {1} is either another keyword (e.g. \"typedef\") or a localized property (e.g. a localized version of \"declaration\""]
}, "{0}, {1}", scope, detail);
}
function decodeUCS16(input: string): number[] {
const output: number[] = [];
let counter: number = 0;
@@ -1471,3 +1462,38 @@ export function isVsCodeInsiders(): boolean {
extensionPath.includes(".vscode-server-exploration");
}
export function stripEscapeSequences(str: string): string {
return str
.replace(/\x1b\[\??[0-9]{0,3}(;[0-9]{1,3})?[a-zA-Z]/g, '')
.replace(/\u0008/g, '')
.replace(/\r/g, '');
}
export function splitLines(data: string): string[] {
return data.split(/\r?\n/g);
}
export function escapeStringForRegex(str: string): string {
return str.replace(/([.*+?^=!:${}()|\[\]\/\\])/g, '\\$1');
}
export function replaceAll(str: string, searchValue: string, replaceValue: string): string {
const pattern: string = escapeStringForRegex(searchValue);
const re: RegExp = new RegExp(pattern, 'g');
return str.replace(re, replaceValue);
}
export interface ISshHostInfo {
hostName: string;
user?: string;
port?: number | string;
}
export interface ISshLocalForwardInfo {
bindAddress?: string;
port?: number | string;
host?: string;
hostPort?: number | string;
localSocket?: string;
remoteSocket?: string;
}
+133
View File
@@ -0,0 +1,133 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { isString, replaceAll } from './common';
import { getOutputChannelLogger } from './logger';
/**
* Support ExpansionVars (${var}), env (${env:var}), and optionally VS CODE commands (${command:commandID}).
* Supported format follows https://code.visualstudio.com/docs/editor/variables-reference
* Expand options and functions are mofidifed from https://github.com/microsoft/vscode-cmake-tools/blob/main/src/expand.ts
*/
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
export interface ExpansionVars {
[key: string]: string;
workspaceFolder: string;
workspaceFolderBasename: string;
}
export interface ExpansionOptions {
vars: ExpansionVars;
doNotSupportCommands?: boolean;
recursive?: boolean;
}
export async function expandAllStrings(obj: any, options: ExpansionOptions): Promise<void> {
if (Array.isArray(obj) || (obj !== null && typeof obj === 'object')) {
for (const key of Object.keys(obj)) {
if (isString(obj[key])) {
obj[key] = await expandString(obj[key], options);
} else {
await expandAllStrings(obj[key], options);
}
}
}
}
export async function expandString(input: string, options: ExpansionOptions): Promise<string> {
const MAX_RECURSION: number = 10;
let result: string = input;
let didReplacement: boolean = false;
let i: number = 0;
do {
// TODO: consider a full circular reference check?
[result, didReplacement] = await expandStringImpl(result, options);
i++;
} while (i < MAX_RECURSION && options.recursive && didReplacement);
if (i === MAX_RECURSION && didReplacement) {
getOutputChannelLogger().showErrorMessage(localize('max.recursion.reached', 'Reached max string expansion recursion. Possible circular reference.'));
}
return replaceAll(result, '${dollar}', '$');
}
/** Returns [expandedString, didReplacement] */
async function expandStringImpl(input: string, options: ExpansionOptions): Promise<[string, boolean]> {
if (!input) {
return [input, false];
}
// We accumulate a list of substitutions that we need to make, preventing
// recursively expanding or looping forever on bad replacements
const subs: Map<string, string> = new Map<string, string>();
const var_re: RegExp = /\$\{(\w+)\}/g;
let match: RegExpMatchArray | null = null;
while ((match = var_re.exec(input))) {
const full: string = match[0];
const key: string = match[1];
if (key !== 'dollar') {
// Replace dollar sign at the very end of the expanding process
const repl: string = options.vars[key];
if (!repl) {
getOutputChannelLogger().showWarningMessage(localize('invalid.var.reference', 'Invalid variable reference {0} in string: {1}.', full, input));
} else {
subs.set(full, repl);
}
}
}
// Regular expression for variable value (between the variable suffix and the next ending curly bracket):
// .+? matches any character (except line terminators) between one and unlimited times,
// as few times as possible, expanding as needed (lazy)
const varValueRegexp: string = ".+?";
const env_re: RegExp = RegExp(`\\$\\{env:(${varValueRegexp})\\}`, "g");
while ((match = env_re.exec(input))) {
const full: string = match[0];
const varname: string = match[1];
if (process.env[varname] === undefined) {
getOutputChannelLogger().showWarningMessage(localize('env.var.not.found', 'Environment variable {0} not found', varname));
}
const repl: string = process.env[varname] || '';
subs.set(full, repl);
}
const command_re: RegExp = RegExp(`\\$\\{command:(${varValueRegexp})\\}`, "g");
while ((match = command_re.exec(input))) {
if (options.doNotSupportCommands) {
getOutputChannelLogger().showWarningMessage(localize('commands.not.supported', 'Commands are not supported for string: {0}.', input));
break;
}
const full: string = match[0];
const command: string = match[1];
if (subs.has(full)) {
continue; // Don't execute commands more than once per string
}
try {
const command_ret: unknown = await vscode.commands.executeCommand(command, options.vars.workspaceFolder);
subs.set(full, `${command_ret}`);
} catch (e: any) {
getOutputChannelLogger().showWarningMessage(localize('exception.executing.command', 'Exception while executing command {0} for string: {1} {2}.', command, input, e));
}
}
let result: string = input;
let didReplacement: boolean = false;
subs.forEach((value, key) => {
if (value !== key) {
result = replaceAll(result, key, value);
didReplacement = true;
}
});
return [result, didReplacement];
}
+76 -1
View File
@@ -8,6 +8,11 @@ import * as vscode from 'vscode';
import * as os from 'os';
import { CppSettings } from './LanguageServer/settings';
import { CppSourceStr } from './LanguageServer/extension';
import * as nls from 'vscode-nls';
import { getLocalizedString, LocalizeStringParams } from './LanguageServer/localization';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
// This is used for testing purposes
let Subscriber: (message: string) => void;
@@ -67,7 +72,10 @@ export class Logger {
}
}
let outputChannel: vscode.OutputChannel | undefined;
export let outputChannel: vscode.OutputChannel | undefined;
export let diagnosticsChannel: vscode.OutputChannel | undefined;
export let debugChannel: vscode.OutputChannel | undefined;
export let warningChannel: vscode.OutputChannel | undefined;
export function getOutputChannel(): vscode.OutputChannel {
if (!outputChannel) {
@@ -81,6 +89,13 @@ export function getOutputChannel(): vscode.OutputChannel {
return outputChannel;
}
export function getDiagnosticsChannel(): vscode.OutputChannel {
if (!diagnosticsChannel) {
diagnosticsChannel = vscode.window.createOutputChannel(localize("c.cpp.diagnostics", "C/C++ Diagnostics"));
}
return diagnosticsChannel;
}
export function showOutputChannel(): void {
getOutputChannel().show();
}
@@ -93,3 +108,63 @@ export function getOutputChannelLogger(): Logger {
}
return outputChannelLogger;
}
export function log(output: string): void {
if (!outputChannel) {
outputChannel = getOutputChannel();
}
outputChannel.appendLine(`${output}`);
}
export interface DebugProtocolParams {
jsonrpc: string;
method: string;
params?: any;
}
export function logDebugProtocol(output: DebugProtocolParams): void {
if (!debugChannel) {
debugChannel = vscode.window.createOutputChannel(`${localize("c.cpp.debug.protocol", "C/C++ Debug Protocol")}`);
}
debugChannel.appendLine("");
debugChannel.appendLine("************************************************************************************************************************");
debugChannel.append(`${output}`);
}
export interface ShowWarningParams {
localizeStringParams: LocalizeStringParams;
}
export function showWarning(params: ShowWarningParams): void {
const message: string = getLocalizedString(params.localizeStringParams);
let showChannel: boolean = false;
if (!warningChannel) {
warningChannel = vscode.window.createOutputChannel(`${localize("c.cpp.warnings", "C/C++ Configuration Warnings")}`);
showChannel = true;
}
// Append before showing the channel, to avoid a delay.
warningChannel.appendLine(`[${new Date().toLocaleString()}] ${message}`);
if (showChannel) {
warningChannel.show(true);
}
}
export function logLocalized(params: LocalizeStringParams): void {
const output: string = getLocalizedString(params);
log(output);
}
export function disposeOutputChannels(): void {
if (outputChannel) {
outputChannel.dispose();
}
if (diagnosticsChannel) {
diagnosticsChannel.dispose();
}
if (debugChannel) {
debugChannel.dispose();
}
if (warningChannel) {
warningChannel.dispose();
}
}
+13 -5
View File
@@ -21,6 +21,8 @@ import { TargetPopulation } from 'vscode-tas-client';
import * as semver from 'semver';
import * as nls from 'vscode-nls';
import { cppBuildTaskProvider, CppBuildTaskProvider } from './LanguageServer/cppBuildTaskProvider';
import { getLocaleId, getLocalizedHtmlPath } from './LanguageServer/localization';
import { disposeOutputChannels, log } from './logger';
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize: nls.LocalizeFunc = nls.loadMessageBundle();
@@ -40,7 +42,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
public async provideTextDocumentContent(uri: vscode.Uri): Promise<string> {
console.assert(uri.path[0] === '/', "A preceeding slash is expected on schema uri path");
const fileName: string = uri.path.substring(1);
const locale: string = util.getLocaleId();
const locale: string = getLocaleId();
let localizedFilePath: string = util.getExtensionFilePath(path.join("dist/schema/", locale, fileName));
const fileExists: boolean = await util.checkFileExists(localizedFilePath);
if (!fileExists) {
@@ -79,7 +81,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
// Read the setting and determine whether we should activate the language server prior to installing callbacks,
// to ensure there is no potential race condition. LanguageServer.activate() is called near the end of this
// function, to allow any further setup to occur here, prior to activation.
const shouldActivateLanguageServer: boolean = (settings.intelliSenseEngine !== "Disabled" && !isOldMacOs);
const isIntelliSenseEngineDisabled: boolean = settings.intelliSenseEngine === "Disabled";
const shouldActivateLanguageServer: boolean = (!isIntelliSenseEngineDisabled && !isOldMacOs);
if (isOldMacOs) {
languageServiceDisabled = true;
@@ -134,19 +137,24 @@ export async function activate(context: vscode.ExtensionContext): Promise<CppToo
if (shouldActivateLanguageServer) {
await LanguageServer.activate();
} else if (isIntelliSenseEngineDisabled) {
// The check here for isIntelliSenseEngineDisabled avoids logging
// the message on old Macs that we've already displayed a warning for.
log(localize("intellisense.disabled", "intelliSenseEngine is Disabled"));
}
return cppTools;
}
export function deactivate(): Thenable<void> {
export async function deactivate(): Promise<void> {
DebuggerExtension.dispose();
Telemetry.deactivate();
disposables.forEach(d => d.dispose());
if (languageServiceDisabled) {
return Promise.resolve();
}
return LanguageServer.deactivate();
await LanguageServer.deactivate();
disposeOutputChannels();
}
async function makeBinariesExecutable(): Promise<void> {
@@ -322,7 +330,7 @@ async function checkVsixCompatibility(): Promise<void> {
if (promise) {
promise.then(async (value) => {
if (value === moreInfoButton) {
await vscode.commands.executeCommand("markdown.showPreview", vscode.Uri.file(util.getLocalizedHtmlPath("Reinstalling the Extension.md")));
await vscode.commands.executeCommand("markdown.showPreview", vscode.Uri.file(getLocalizedHtmlPath("Reinstalling the Extension.md")));
} else if (value === ignoreButton) {
ignoreMismatchedCompatibleVsix.Value = true;
}
+3 -3
View File
@@ -4,7 +4,7 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import TelemetryReporter from 'vscode-extension-telemetry';
import TelemetryReporter from '@vscode/extension-telemetry';
import { getExperimentationServiceAsync, IExperimentationService, IExperimentationTelemetry, TargetPopulation } from 'vscode-tas-client';
import * as util from './common';
@@ -89,11 +89,11 @@ export async function deactivate(): Promise<void> {
}
}
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }): void {
export function logDebuggerEvent(eventName: string, properties?: { [key: string]: string }, metrics?: { [key: string]: number }): void {
const sendTelemetry = () => {
if (experimentationTelemetry) {
const eventNamePrefix: string = "cppdbg/VS/Diagnostics/Debugger/";
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties);
experimentationTelemetry.sendTelemetryEvent(eventNamePrefix + eventName, properties, metrics);
}
};
+2 -1
View File
@@ -14,6 +14,7 @@
"include": [
"test/**/*.ts",
"tools/**/*.ts",
"ui/**/*.ts"
"ui/**/*.ts",
"./vscode*.d.ts"
]
}
+46
View File
@@ -0,0 +1,46 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as assert from "assert";
import { ExpansionOptions, expandAllStrings, expandString } from "../../src/expand";
suite('Var expansion validation', () => {
test('Expand all strings', async () => {
const input: object = {
in1: "${test2}",
in2: "${test4}",
in3: [
"${test3}",
{
in4: "${test3}"
}
]
};
const variables: object = {
test1: "t1",
test2: "${dollar}{${test1}}",
test3: "test${test2}test:${env:envtest}:${dollar}test",
test4: "${test4}"
};
const expansionOptions: ExpansionOptions = {
vars: {
workspaceFolder: '{workspaceFolder}',
workspaceFolderBasename: '{workspaceFolderBasename}',
...variables
},
recursive: true
};
await expandAllStrings(input, expansionOptions);
assert.deepStrictEqual(input, {
in1: "${t1}",
in2: "${test4}",
in3: [
"test${t1}test::$test",
{
in4: "test${t1}test::$test"
}
]
});
});
});
+8 -7
View File
@@ -53,7 +53,7 @@ function updateDefaults(object: any, defaults: any): any {
}
function refReplace(definitions: any, ref: any): any {
// $ref is formatted as "#/definitions/ObjectName"
// $ref is formatted as "#/definitions/ObjectName"
const referenceStringArray: string[] = ref['$ref'].split('/');
// Getting "ObjectName"
@@ -82,11 +82,7 @@ function replaceReferences(definitions: any, objects: any): any {
// Handle 'anyOf' with references
if (objects[key].hasOwnProperty('anyOf')) {
for (const index in objects[key].anyOf) {
if (objects[key].anyOf[index].hasOwnProperty('$ref')) {
objects[key].anyOf[index] = refReplace(definitions, objects[key].anyOf[index]);
}
}
objects[key].anyOf = replaceReferences(definitions, objects[key].anyOf);
}
// Recursively replace references if this object has properties.
@@ -95,10 +91,15 @@ function replaceReferences(definitions: any, objects: any): any {
objects[key].properties = updateDefaults(objects[key].properties, objects[key].default);
}
// Recursively replace references if the array has objects in items.
// Items in array contains ref
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null && objects[key].items.hasOwnProperty('$ref')) {
objects[key].items = refReplace(definitions, objects[key].items);
}
// Recursively replace references if the array has objects that contains ref in items.
if (objects[key].hasOwnProperty('type') && objects[key].type === "array" && objects[key].items !== null) {
objects[key].items = replaceReferences(definitions, objects[key].items);
}
}
return objects;
+321 -2
View File
@@ -193,6 +193,313 @@
}
}
},
"Variables": {
"type": "object",
"description": "%c_cpp.debuggers.variables.description%",
"default": {
"<variable-name>": "<variable-value>"
},
"properties": {},
"additionalProperties": {
"type": "string",
"description": "%c_cpp.debuggers.variables.properties.description%",
"default": ""
}
},
"VsCodeCommand": {
"type": "object",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.description%",
"default": "",
"enum": [
"command"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.vsCodeCommand.command.description%",
"default": ""
},
"args": {
"type": "array",
"description": "%c_cpp.debuggers.vsCodeCommand.args.description%",
"items": {
"type": "string"
}
}
}
},
"Host": {
"type": "object",
"description": "%c_cpp.debuggers.host.description%",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
},
"jumpHosts": {
"type": "array",
"description": "%c_cpp.debuggers.host.jumpHost.description%",
"items": {
"type": "object",
"default": {},
"required": [
"hostName"
],
"properties": {
"user": {
"type": "string",
"description": "%c_cpp.debuggers.host.user.description%",
"default": ""
},
"hostName": {
"type": "string",
"description": "%c_cpp.debuggers.host.hostName.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.port.description%",
"default": 22
}
}
}
},
"localForwards": {
"type": "array",
"description": "%c_cpp.debuggers.host.localForward.description%",
"items": {
"type": "object",
"default": {},
"properties": {
"bindAddress": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.bindAddress.description%",
"default": ""
},
"port": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.port.description%"
},
"host": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.host.description%",
"default": ""
},
"hostPort": {
"anyOf": [
{
"type": "number"
},
{
"type": "string",
"pattern": "^\\d+$|^\\${.+}$"
}
],
"description": "%c_cpp.debuggers.host.localForward.hostPort.description%"
},
"localSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.localSocket.description%",
"default": ""
},
"remoteSocket": {
"type": "string",
"description": "%c_cpp.debuggers.host.localForward.remoteSocket.description%",
"default": ""
}
}
}
}
}
},
"DeploySteps": {
"type": "array",
"description": "%c_cpp.debuggers.deploySteps.description%",
"items": {
"anyOf": [
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": {},
"required": [
"type",
"files",
"host",
"targetDir"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.description%",
"default": "",
"enum": [
"scp"
]
},
"files": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "%c_cpp.debuggers.deploySteps.scp.files.description%",
"default": ""
},
"host": {
"$ref": "#/definitions/Host"
},
"targetDir": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.targetDir.description%",
"default": ""
},
"scpPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.scp.scpPath.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": {},
"required": [
"type",
"host",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.description%",
"default": "",
"enum": [
"ssh"
]
},
"host": {
"$ref": "#/definitions/Host"
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.command.description%",
"default": ""
},
"sshPath": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.ssh.sshPath.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"type": "object",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": {},
"required": [
"type",
"command"
],
"properties": {
"type": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.description%",
"default": "",
"enum": [
"shell"
]
},
"command": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.shell.command.description%",
"default": ""
},
"continueOn": {
"type": "string",
"description": "%c_cpp.debuggers.deploySteps.continueOn.description%",
"default": ""
},
"debug": {
"type": "boolean",
"description": "%c_cpp.debuggers.deploySteps.debug%"
}
}
},
{
"$ref": "#/definitions/VsCodeCommand"
}
]
},
"default": []
},
"CppdbgLaunchOptions": {
"type": "object",
"required": [
@@ -253,8 +560,8 @@
},
"launchCompleteCommand": {
"enum": [
"exec-run",
"exec-continue",
"exec-run",
"exec-continue",
"None"
],
"description": "%c_cpp.debuggers.launchCompleteCommand.description%",
@@ -399,6 +706,12 @@
"$ref": "#/definitions/HardwareBreakpoints",
"description": "%c_cpp.debuggers.hardwareBreakpoints.description%",
"default": {}
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},
@@ -513,6 +826,12 @@
"symbolLoadInfo": {
"$ref": "#/definitions/SymbolLoadInfo",
"description": "%c_cpp.debuggers.symbolLoadInfo.description%"
},
"variables": {
"$ref": "#/definitions/Variables"
},
"deploySteps": {
"$ref": "#/definitions/DeploySteps"
}
}
},
+1 -1
View File
@@ -15,7 +15,7 @@
},
"include": [
"src/**/*.ts",
"./node_modules/vscode/vscode.d.ts",
"./vscode*.d.ts",
"./node_modules/vscode/lib/*"
]
}
+121 -40
View File
@@ -44,14 +44,14 @@
resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.2.tgz#8f03a22a04de437254e8ce8cc84ba39689288752"
integrity sha512-HyYEUDeIj5rRQU2Hk5HTB2uHsbRQpF70nvMhVzi+VJR0X+xNEhjPui4/kBf3VeH/wqD28PT4sVOm8qqLjBrSZg==
"@es-joy/jsdoccomment@0.10.8":
version "0.10.8"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.10.8.tgz#b3152887e25246410ed4ea569a55926ec13b2b05"
integrity sha512-3P1JiGL4xaR9PoTKUHa2N/LKwa2/eUdRqGwijMWWgBqbFEqJUVpmaOi2TcjcemrsRMgFLBzQCK4ToPhrSVDiFQ==
"@es-joy/jsdoccomment@~0.31.0":
version "0.31.0"
resolved "https://registry.yarnpkg.com/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz#dbc342cc38eb6878c12727985e693eaef34302bc"
integrity sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==
dependencies:
comment-parser "1.2.4"
comment-parser "1.3.1"
esquery "^1.4.0"
jsdoc-type-pratt-parser "1.1.1"
jsdoc-type-pratt-parser "~3.1.0"
"@eslint/eslintrc@^0.4.3":
version "0.4.3"
@@ -101,6 +101,42 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz#b520529ec21d8e5945a1851dfd1c32e94e39ff45"
integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==
"@microsoft/[email protected]", "@microsoft/1ds-core-js@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@microsoft/1ds-core-js/-/1ds-core-js-3.2.3.tgz#2217d92ec8b073caa4577a13f40ea3a5c4c4d4e7"
integrity sha512-796A8fd90oUKDRO7UXUT9BwZ3G+a9XzJj5v012FcCN/2qRhEsIV3x/0wkx2S08T4FiQEUPkB2uoYHpEjEneM7g==
dependencies:
"@microsoft/applicationinsights-core-js" "2.8.4"
"@microsoft/applicationinsights-shims" "^2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/1ds-post-js@^3.2.3":
version "3.2.3"
resolved "https://registry.yarnpkg.com/@microsoft/1ds-post-js/-/1ds-post-js-3.2.3.tgz#1fa7d51615a44f289632ae8c588007ba943db216"
integrity sha512-tcGJQXXr2LYoBbIXPoUVe1KCF3OtBsuKDFL7BXfmNtuSGtWF0yejm6H83DrR8/cUIGMRMUP9lqNlqFGwDYiwAQ==
dependencies:
"@microsoft/1ds-core-js" "3.2.3"
"@microsoft/applicationinsights-shims" "^2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/[email protected]":
version "2.8.4"
resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-core-js/-/applicationinsights-core-js-2.8.4.tgz#607e531bb241a8920d43960f68a7c76a6f9af596"
integrity sha512-FoA0FNOsFbJnLyTyQlYs6+HR7HMEa6nAOE6WOm9WVejBHMHQ/Bdb+hfVFi6slxwCimr/ner90jchi4/sIYdnyQ==
dependencies:
"@microsoft/applicationinsights-shims" "2.0.1"
"@microsoft/dynamicproto-js" "^1.1.6"
"@microsoft/[email protected]", "@microsoft/applicationinsights-shims@^2.0.1":
version "2.0.1"
resolved "https://registry.yarnpkg.com/@microsoft/applicationinsights-shims/-/applicationinsights-shims-2.0.1.tgz#5d72fb7aaf4056c4fda54f9d7c93ccf8ca9bcbfd"
integrity sha512-G0MXf6R6HndRbDy9BbEj0zrLeuhwt2nsXk2zKtF0TnYo39KgYqhYC2ayIzKPTm2KAE+xzD7rgyLdZnrcRvt9WQ==
"@microsoft/dynamicproto-js@^1.1.6":
version "1.1.6"
resolved "https://registry.yarnpkg.com/@microsoft/dynamicproto-js/-/dynamicproto-js-1.1.6.tgz#6fe03468862861f5f88ac4c3959a652b3797f1bc"
integrity sha512-D1Oivw1A4bIXhzBIy3/BBPn3p2On+kpO2NiYt9shICDK7L/w+cR6FFBUsBZ05l6iqzTeL+Jm8lAYn0g6G7DmDg==
"@nodelib/[email protected]":
version "2.1.4"
resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.4.tgz#d4b3549a5db5de2683e0c1071ab4f140904bbf69"
@@ -254,6 +290,14 @@
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.46.tgz#0fb6bfbbeabd7a30880504993369c4bf1deab1fe"
integrity sha512-laIjwTQaD+5DukBZaygQ79K1Z0jb1bPEMRrkXSLjtCcZm+abyp5YbrqpSLzD42FwWW6gK/aS4NYpJ804nG2brg==
"@types/glob@^7.1.3":
version "7.2.0"
resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
dependencies:
"@types/minimatch" "*"
"@types/node" "*"
"@types/json-schema@*", "@types/json-schema@^7.0.6":
version "7.0.7"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
@@ -269,6 +313,11 @@
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4=
"@types/minimatch@*":
version "3.0.5"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
"@types/minimatch@^3.0.3":
version "3.0.3"
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
@@ -316,11 +365,6 @@
resolved "https://registry.yarnpkg.com/@types/tmp/-/tmp-0.1.0.tgz#19cf73a7bcf641965485119726397a096f0049bd"
integrity sha512-6IwZ9HzWbCq6XoQWhxLpDjuADodH/MKXRUIDFudvgjcVdjFknvmR+DNsoUeer4XPrEnrZs04Jj+kfV9pFsrhmA==
"@types/[email protected]":
version "1.65.0"
resolved "https://registry.yarnpkg.com/@types/vscode/-/vscode-1.65.0.tgz#042dd8d93c32ac62cb826cd0fa12376069d1f448"
integrity sha512-wQhExnh2nEzpjDMSKhUvnNmz3ucpd3E+R7wJkOhBNK3No6fG3VUdmVmMOKD0A8NDZDDDiQcLNxe3oGmX5SjJ5w==
"@types/which@^1.3.2":
version "1.3.2"
resolved "https://registry.yarnpkg.com/@types/which/-/which-1.3.2.tgz#9c246fc0c93ded311c8512df2891fb41f6227fdf"
@@ -415,6 +459,14 @@
resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44"
integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==
"@vscode/extension-telemetry@^0.6.2":
version "0.6.2"
resolved "https://registry.yarnpkg.com/@vscode/extension-telemetry/-/extension-telemetry-0.6.2.tgz#b86814ee680615730da94220c2b03ea9c3c14a8e"
integrity sha512-yb/wxLuaaCRcBAZtDCjNYSisAXz3FWsSqAha5nhHcYxx2ZPdQdWuZqVXGKq0ZpHVndBWWtK6XqtpCN2/HB4S1w==
dependencies:
"@microsoft/1ds-core-js" "^3.2.3"
"@microsoft/1ds-post-js" "^3.2.3"
"@vscode/test-electron@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-1.6.1.tgz#2b282154097e250ee9b94b6a284eb5804e53a3d7"
@@ -1332,10 +1384,10 @@ comment-json@^4.1.1:
has-own-prop "^2.0.0"
repeat-string "^1.6.1"
comment-parser@1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.2.4.tgz#489f3ee55dfd184a6e4bffb31baba284453cb760"
integrity sha512-pm0b+qv+CkWNriSTMsfnjChF9kH0kxz55y44Wo5le9qLxMj5xDQAaEd9ZN1ovSuk9CsrncWaFwgpOMg7ClJwkw==
comment-parser@1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/comment-parser/-/comment-parser-1.3.1.tgz#3d7ea3adaf9345594aedee6563f422348f165c1b"
integrity sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==
component-emitter@^1.2.1:
version "1.3.0"
@@ -1453,7 +1505,7 @@ [email protected]:
dependencies:
ms "^2.1.1"
debug@4, debug@^4.3.2:
debug@4:
version "4.3.2"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b"
integrity sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==
@@ -1488,6 +1540,13 @@ debug@^4.0.1, debug@^4.1.1:
dependencies:
ms "^2.1.1"
debug@^4.3.4:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
dependencies:
ms "2.1.2"
decamelize@^1.1.1, decamelize@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
@@ -1870,19 +1929,17 @@ eslint-plugin-import@^2.24.2:
resolve "^1.20.0"
tsconfig-paths "^3.11.0"
eslint-plugin-jsdoc@^36.1.0:
version "36.1.0"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-36.1.0.tgz#8dfe5f27edfb6aa3812e6d86ccaea849ddc86b03"
integrity sha512-Qpied2AJCQcScxfzTObLKRiP5QgLXjMU/ITjBagEV5p2Q/HpumD1EQtazdRYdjDSwPmXhwOl2yquwOGQ4HOJNw==
eslint-plugin-jsdoc@^39.3.3:
version "39.3.3"
resolved "https://registry.yarnpkg.com/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.3.tgz#75dd67ce581e7527a69f27800138cc0f9c388236"
integrity sha512-K/DAjKRUNaUTf0KQhI9PvsF+Y3mGDx/j0pofXsJCQe/tmRsRweBIXR353c8nAro0lytZYEf7l0PluBpzKDiHxw==
dependencies:
"@es-joy/jsdoccomment" "0.10.8"
comment-parser "1.2.4"
debug "^4.3.2"
"@es-joy/jsdoccomment" "~0.31.0"
comment-parser "1.3.1"
debug "^4.3.4"
escape-string-regexp "^4.0.0"
esquery "^1.4.0"
jsdoc-type-pratt-parser "^1.1.1"
lodash "^4.17.21"
regextras "^0.8.0"
semver "^7.3.5"
semver "^7.3.7"
spdx-expression-parse "^3.0.1"
eslint-scope@^5.0.0:
@@ -3407,10 +3464,10 @@ js-yaml@^3.13.1:
argparse "^1.0.7"
esprima "^4.0.0"
jsdoc-type-pratt-parser@1.1.1, jsdoc-type-pratt-parser@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-1.1.1.tgz#10fe5e409ba38de22a48b555598955a26ff0160f"
integrity sha512-uelRmpghNwPBuZScwgBG/OzodaFk5RbO5xaivBdsAY70icWfShwZ7PCMO0x1zSkOa8T1FzHThmrdoyg/0AwV5g==
jsdoc-type-pratt-parser@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz#a4a56bdc6e82e5865ffd9febc5b1a227ff28e67e"
integrity sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==
json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2:
version "1.0.2"
@@ -3477,6 +3534,11 @@ kind-of@^6.0.0, kind-of@^6.0.2:
resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd"
integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==
kleur@^3.0.3:
version "3.0.3"
resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e"
integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==
last-run@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/last-run/-/last-run-1.1.1.tgz#45b96942c17b1c79c772198259ba943bebf8ca5b"
@@ -4432,6 +4494,14 @@ progress@^2.0.0:
resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
prompts@^2.1.0:
version "2.4.2"
resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069"
integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==
dependencies:
kleur "^3.0.3"
sisteransi "^1.0.5"
prr@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
@@ -4585,11 +4655,6 @@ regexpp@^3.1.0:
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
regextras@^0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/regextras/-/regextras-0.8.0.tgz#ec0f99853d4912839321172f608b544814b02217"
integrity sha512-k519uI04Z3SaY0fLX843MRXnDeG2+vHOFsyhiPZvNLe7r8rD2YNRjq4BQLZZ0oAr2NrtvZlICsXysGNFPGa3CQ==
remove-bom-buffer@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz#c2bf1e377520d324f623892e33c10cac2c252b53"
@@ -4818,6 +4883,13 @@ semver@^7.2.1, semver@^7.3.4, semver@^7.3.5:
dependencies:
lru-cache "^6.0.0"
semver@^7.3.7:
version "7.3.7"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f"
integrity sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==
dependencies:
lru-cache "^6.0.0"
[email protected], serialize-javascript@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-5.0.1.tgz#7886ec848049a462467a97d3d918ebb2aaf934f4"
@@ -4898,6 +4970,11 @@ signal-exit@^3.0.3:
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==
sisteransi@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed"
integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==
slash@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"
@@ -5790,10 +5867,14 @@ [email protected], vscode-debugprotocol@^1.35.0:
resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.38.0.tgz#7a9bcd457e6642f48fabef114c0fa1c25a2fb1e7"
integrity sha512-oam9iSjNfXSn71a8bmNsXv8k/rIKSOcllIPrFnNgxd1EMBpfnum+gb7lmRpcH0zSjGb+OH8Ncn8B5tv8srWbNQ==
vscode-extension-telemetry@^0.4.4:
version "0.4.4"
resolved "https://registry.yarnpkg.com/vscode-extension-telemetry/-/vscode-extension-telemetry-0.4.4.tgz#e5d5ac90ea7d07ec054f5310893d95d43d5984b0"
integrity sha512-LzirNf2GnykXCAqqWrvj+snYqgkPVyjwM72tYOHgcZiG/ZRuNjmqlgvs+SomEJdmD8cutduitPmhoyIuzOrVfA==
vscode-dts@^0.3.2:
version "0.3.3"
resolved "https://registry.yarnpkg.com/vscode-dts/-/vscode-dts-0.3.3.tgz#e5ef3afe76182875b252cca7f449938e4a0bf28a"
integrity sha512-JfOsWL0NvfVw0UF9bcTjlv1Onz3Ted7cgpPWKWMnHGB+72t/tn8WFDeKLZO42l2k9KJq/NGS9rFC5gZbyI4FTg==
dependencies:
minimist "^1.2.0"
prompts "^2.1.0"
rimraf "^3.0.0"
vscode-jsonrpc@^4.0.0:
version "4.0.0"