Compare commits

...
33 changed files with 7003 additions and 6827 deletions
+4
View File
@@ -62,6 +62,8 @@ module.exports = {
"no-case-declarations": "off",
"no-useless-escape": "off",
"no-floating-decimal": "error",
"keyword-spacing": ["error", { "before": true, "overrides": { "this": { "before": false } } }],
"arrow-spacing": ["error", { "before": true, "after": true }],
"@typescript-eslint/no-for-in-array": "error",
"@typescript-eslint/no-misused-new": "error",
"@typescript-eslint/no-misused-promises": "error",
@@ -85,6 +87,8 @@ module.exports = {
"@typescript-eslint/no-unnecessary-boolean-literal-compare": "error",
"arrow-body-style": "error",
"comma-dangle": "error",
"comma-spacing": "off",
"@typescript-eslint/comma-spacing": "error",
"constructor-super": "error",
"curly": "error",
"eol-last": "error",
+141 -141
View File
@@ -1,143 +1,143 @@
// A launch configuration that compiles the extension and then opens it inside a new window
{
"version": "0.1.0",
"configurations": [
{
"name": "Launch Extension (development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev",
},
{
"name": "Launch Extension (production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile",
},
{
"name": "Launch Extension (do not build)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
},
{
"name": "Launch Extension (watch, development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev Watch",
},
{
"name": "Launch Extension (watch, production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile Watch",
},
{
"name": "Launch Unit Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/unitTests/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Launch Integration Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/test/integrationTests/testAssets/SimpleCppProject/simpleCppProject.code-workspace",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/languageServer/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest",
},
{
"name": "Launch E2E IntelliSense features tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"C:/git/Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/IntelliSenseFeatures/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Node Attach",
"type": "node",
"request": "attach",
"port": 5858
},
{
"name": "MochaTest",
"type": "node",
"request": "attach",
"port": 9229,
"continueOnAttach": true,
"autoAttachChildProcesses": false,
"skipFiles": [
"<node_internals>/**"
],
"outFiles": [
"${workspaceFolder}/**/out/**/*.js",
"!**/node_modules/**"
]
}
]
}
"version": "0.1.0",
"configurations": [
{
"name": "Launch Extension (development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev",
},
{
"name": "Launch Extension (production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile",
},
{
"name": "Launch Extension (do not build)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
]
},
{
"name": "Launch Extension (watch, development)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "Compile Dev Watch",
},
{
"name": "Launch Extension (watch, production)",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/dist/**/*.js"
],
"preLaunchTask": "TypeScript Compile Watch",
},
{
"name": "Launch Unit Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/unitTests/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Launch Integration Tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/test/integrationTests/testAssets/SimpleCppProject/simpleCppProject.code-workspace",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/languageServer/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest",
},
{
"name": "Launch E2E IntelliSense features tests",
"type": "extensionHost",
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"${workspaceFolder}/../../Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace",
"--extensionDevelopmentPath=${workspaceFolder}",
"--extensionTestsPath=${workspaceFolder}/out/test/integrationTests/IntelliSenseFeatures/index"
],
"sourceMaps": true,
"outFiles": [
"${workspaceFolder}/out/test/**/*.js"
],
"preLaunchTask": "Pretest"
},
{
"name": "Node Attach",
"type": "node",
"request": "attach",
"port": 5858
},
{
"name": "MochaTest",
"type": "node",
"request": "attach",
"port": 9229,
"continueOnAttach": true,
"autoAttachChildProcesses": false,
"skipFiles": [
"<node_internals>/**"
],
"outFiles": [
"${workspaceFolder}/**/out/**/*.js",
"!**/node_modules/**"
]
}
]
}
+4 -2
View File
@@ -9,8 +9,8 @@
"typescript.tsdk": "./node_modules/typescript/lib", // we want to use the TS server from our node_modules folder to control its version
// if you install the mocha test explorer extension, you can run the unit tests from the test explorer UI
"testExplorer.useNativeTesting": true,
"mochaExplorer.files": "./**/internalUnitTests/**/test-*.js",
"mochaExplorer.watch": "./**/internalUnitTests/**/test-*.js",
"mochaExplorer.files": "./**/internalUnitTests/**/*.test.js",
"mochaExplorer.watch": "./**/internalUnitTests/**/*.test.js",
"mochaExplorer.ignore": [
"**/*skip*",
"**/dist/test/**/*.d.ts",
@@ -24,11 +24,13 @@
],
"mochaExplorer.monkeyPatch": true,
"[json]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.json-language-features",
"editor.tabSize": 4,
"files.insertFinalNewline": true
},
"[jsonc]": {
"editor.formatOnSave": true,
"editor.defaultFormatter": "vscode.json-language-features",
"editor.tabSize": 4,
"files.insertFinalNewline": true
+6091 -6091
View File
File diff suppressed because it is too large Load Diff
@@ -104,8 +104,7 @@ export class CallHierarchyProvider implements vscode.CallHierarchyProvider {
}
public async prepareCallHierarchy(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken): Promise<vscode.CallHierarchyItem | undefined> {
await this.client.ready;
await processDelayedDidOpen(document);
await this.client.enqueue(() => processDelayedDidOpen(document));
workspaceReferences.cancelCurrentReferenceRequest(CancellationSender.NewRequest);
workspaceReferences.clearViews();
@@ -57,8 +57,7 @@ export class DocumentSymbolProvider implements vscode.DocumentSymbolProvider {
const client: Client = clients.getClientFor(document.uri);
if (client instanceof DefaultClient) {
const defaultClient: DefaultClient = <DefaultClient>client;
await client.ready;
await processDelayedDidOpen(document);
await client.enqueue(() => processDelayedDidOpen(document));
const params: GetDocumentSymbolRequestParams = {
uri: document.uri.toString()
};
@@ -23,8 +23,8 @@ export class FoldingRangeProvider implements vscode.FoldingRangeProvider {
const params: GetFoldingRangesParams = {
uri: document.uri.toString()
};
await this.client.ready;
await processDelayedDidOpen(document);
await this.client.enqueue(() => processDelayedDidOpen(document));
const response: GetFoldingRangesResult = await this.client.languageClient.sendRequest(GetFoldingRangesRequest, params, token);
if (token.isCancellationRequested || response.ranges === undefined) {
@@ -55,9 +55,7 @@ export class InlayHintsProvider implements vscode.InlayHintsProvider {
public async provideInlayHints(document: vscode.TextDocument, range: vscode.Range,
token: vscode.CancellationToken): Promise<vscode.InlayHint[] | undefined> {
await this.client.ready;
await processDelayedDidOpen(document);
await this.client.enqueue(() => processDelayedDidOpen(document));
const uriString: string = document.uri.toString();
// Get results from cache if available.
@@ -26,8 +26,7 @@ export class SemanticTokensProvider implements vscode.DocumentSemanticTokensProv
const tokens: vscode.SemanticTokens = builder.build();
return tokens;
}
await this.client.ready;
await processDelayedDidOpen(document);
await this.client.enqueue(() => processDelayedDidOpen(document));
const uriString: string = document.uri.toString();
// First check the semantic token cache to see if we already have results for that file and version
+298 -213
View File
@@ -22,7 +22,7 @@ import { SemanticTokensProvider } from './Providers/semanticTokensProvider';
import { WorkspaceSymbolProvider } from './Providers/workspaceSymbolProvider';
// End provider imports
import { fail } from 'assert';
import { ok } from 'assert';
import * as fs from 'fs';
import * as os from 'os';
import { SourceFileConfiguration, SourceFileConfigurationItem, Version, WorkspaceBrowseConfiguration } from 'vscode-cpptools';
@@ -32,6 +32,8 @@ import { LanguageClient, ServerOptions } from 'vscode-languageclient/node';
import * as nls from 'vscode-nls';
import { DebugConfigurationProvider } from '../Debugger/configurationProvider';
import { CustomConfigurationProvider1, getCustomConfigProviders, isSameProviderExtensionId } from '../LanguageServer/customProviders';
import { ManualPromise } from '../Utility/Async/manualPromise';
import { ManualSignal } from '../Utility/Async/manualSignal';
import { logAndReturn, returns } from '../Utility/Async/returns';
import * as util from '../common';
import { DebugProtocolParams, Logger, ShowWarningParams, getDiagnosticsChannel, getOutputChannelLogger, logDebugProtocol, logLocalized, showWarning } from '../logger';
@@ -80,7 +82,6 @@ let languageClient: LanguageClient;
let firstClientStarted: Promise<void>;
let languageClientCrashedNeedsRestart: boolean = false;
const languageClientCrashTimes: number[] = [];
let pendingTask: util.BlockingTask<any> | undefined;
let compilerDefaults: configs.CompilerDefaults | undefined;
let diagnosticsCollectionIntelliSense: vscode.DiagnosticCollection;
let diagnosticsCollectionRefactor: vscode.DiagnosticCollection;
@@ -718,6 +719,7 @@ class ClientModel {
export interface Client {
readonly ready: Promise<void>;
enqueue<T>(task: () => Promise<T>): Promise<T>;
InitializingWorkspaceChanged: vscode.Event<boolean>;
IndexingWorkspaceChanged: vscode.Event<boolean>;
ParsingWorkspaceChanged: vscode.Event<boolean>;
@@ -843,6 +845,20 @@ export class DefaultClient implements Client {
private configStateReceived: ConfigStateReceived = { compilers: false, compileCommands: false, configProviders: undefined, timeout: false };
private showConfigureIntelliSenseButton: boolean = false;
/** A queue of asynchronous tasks that need to be processed befofe ready is considered active. */
private static queue = new Array<[ManualPromise<unknown>, () => Promise<unknown>]|[ManualPromise<unknown>]>();
/** returns a promise that waits initialization and/or a change to configuration to complete (i.e. language client is ready-to-use) */
private static readonly isStarted = new ManualSignal<void>(true);
/**
* Indicates if the blocking task dispatcher is currently running
*
* This will be in the Set state when the dispatcher is not running (ie, if you await this it will be resolved immediately)
* If the dispatcher is running, this will be in the Reset state (ie, if you await this it will be resolved when the dispatcher is done)
*/
private static readonly dispatching = new ManualSignal<void>();
// The "model" that is displayed via the UI (status bar).
private model: ClientModel = new ClientModel();
@@ -1256,7 +1272,7 @@ export class DefaultClient implements Client {
// Semantic token types are identified by indexes in this list of types, in the legend.
const tokenTypesLegend: string[] = [];
for (const e in SemanticTokenTypes) {
// An enum is actually a set of mappings from key <=> value. Enumerate over only the names.
// An enum is actually a set of mappings from key <=> value. Enumerate over only the names.
// This allow us to represent the constants using an enum, which we can match in native code.
if (isNaN(Number(e))) {
tokenTypesLegend.push(e);
@@ -1303,91 +1319,8 @@ export class DefaultClient implements Client {
util.setProgress(util.getProgressExecutableStarted());
isFirstClient = true;
}
void this.init(rootUri, isFirstClient).catch(logAndReturn.undefined);
// requests/notifications are deferred until this.languageClient is set.
void this.queueBlockingTask(async () => {
ui = getUI();
ui.bind(this);
await firstClientStarted;
try {
const workspaceFolder: vscode.WorkspaceFolder | undefined = this.rootFolder;
this.innerConfiguration = new configs.CppProperties(this, rootUri, workspaceFolder);
this.innerConfiguration.ConfigurationsChanged((e) => this.onConfigurationsChanged(e));
this.innerConfiguration.SelectionChanged((e) => this.onSelectedConfigurationChanged(e));
this.innerConfiguration.CompileCommandsChanged((e) => this.onCompileCommandsChanged(e));
this.disposables.push(this.innerConfiguration);
this.innerLanguageClient = languageClient;
telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings());
failureMessageShown = false;
if (isFirstClient) {
workspaceReferences = new refs.ReferencesManager(this);
// Only register file watchers and providers after the extension has finished initializing,
// e.g. prevents empty c_cpp_properties.json from generation.
this.registerFileWatcher();
initializedClientCount = 0;
this.inlayHintsProvider = new InlayHintsProvider(this);
this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider));
this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, new RenameProvider(this)));
this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, new FindAllReferencesProvider(this)));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this)));
this.disposables.push(vscode.languages.registerDocumentSymbolProvider(util.documentSelector, new DocumentSymbolProvider(), undefined));
this.disposables.push(vscode.languages.registerCodeActionsProvider(util.documentSelector, new CodeActionProvider(this), undefined));
this.disposables.push(vscode.languages.registerCallHierarchyProvider(util.documentSelector, new CallHierarchyProvider(this)));
// Because formatting and codeFolding can vary per folder, we need to register these providers once
// and leave them registered. The decision of whether to provide results needs to be made on a per folder basis,
// within the providers themselves.
this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(util.documentSelector, new DocumentFormattingEditProvider(this));
this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(util.documentSelector, new DocumentRangeFormattingEditProvider(this));
this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(util.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n");
this.codeFoldingProvider = new FoldingRangeProvider(this);
this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(util.documentSelector, this.codeFoldingProvider);
const settings: CppSettings = new CppSettings();
if (settings.enhancedColorization && semanticTokensLegend) {
this.semanticTokensProvider = new SemanticTokensProvider(this);
this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend);
}
// Listen for messages from the language server.
this.registerNotifications();
}
// update all client configurations
this.configuration.setupConfigurations();
initializedClientCount++;
// count number of clients, once all clients are configured, check for trusted compiler to display notification to user and add a short delay to account for config provider logic to finish
if ((vscode.workspace.workspaceFolders === undefined) || (initializedClientCount >= vscode.workspace.workspaceFolders.length)) {
// Timeout waiting for compile_commands.json and config providers.
// The quick pick options will update if they're added later on.
clients.forEach(client => {
if (client instanceof DefaultClient) {
global.setTimeout(() => {
client.configStateReceived.timeout = true;
void client.handleConfigStatusOrPrompt();
}, 15000);
}
});
// The configurations will not be sent to the language server until the default include paths and frameworks have been set.
// The event handlers must be set before this happens.
compilerDefaults = await this.requestCompiler();
DefaultClient.updateClientConfigurations();
clients.forEach(client => {
if (client instanceof DefaultClient) {
client.configStateReceived.compilers = true;
void client.handleConfigStatusOrPrompt();
}
});
}
} catch (err) {
this.isSupported = false; // Running on an OS we don't support yet.
if (!failureMessageShown) {
failureMessageShown = true;
void vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", String(err)));
}
}
});
} catch (errJS) {
const err: NodeJS.ErrnoException = errJS as NodeJS.ErrnoException;
this.isSupported = false; // Running on an OS we don't support yet.
@@ -1404,6 +1337,92 @@ export class DefaultClient implements Client {
}
}
private async init(rootUri: vscode.Uri | undefined, isFirstClient: boolean) {
ui = getUI();
ui.bind(this);
await firstClientStarted;
try {
const workspaceFolder: vscode.WorkspaceFolder | undefined = this.rootFolder;
this.innerConfiguration = new configs.CppProperties(this, rootUri, workspaceFolder);
this.innerConfiguration.ConfigurationsChanged((e) => this.onConfigurationsChanged(e));
this.innerConfiguration.SelectionChanged((e) => this.onSelectedConfigurationChanged(e));
this.innerConfiguration.CompileCommandsChanged((e) => this.onCompileCommandsChanged(e));
this.disposables.push(this.innerConfiguration);
this.innerLanguageClient = languageClient;
telemetry.logLanguageServerEvent("NonDefaultInitialCppSettings", this.settingsTracker.getUserModifiedSettings());
failureMessageShown = false;
if (isFirstClient) {
workspaceReferences = new refs.ReferencesManager(this);
// Only register file watchers and providers after the extension has finished initializing,
// e.g. prevents empty c_cpp_properties.json from generation.
this.registerFileWatcher();
initializedClientCount = 0;
this.inlayHintsProvider = new InlayHintsProvider(this);
this.disposables.push(vscode.languages.registerInlayHintsProvider(util.documentSelector, this.inlayHintsProvider));
this.disposables.push(vscode.languages.registerRenameProvider(util.documentSelector, new RenameProvider(this)));
this.disposables.push(vscode.languages.registerReferenceProvider(util.documentSelector, new FindAllReferencesProvider(this)));
this.disposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(this)));
this.disposables.push(vscode.languages.registerDocumentSymbolProvider(util.documentSelector, new DocumentSymbolProvider(), undefined));
this.disposables.push(vscode.languages.registerCodeActionsProvider(util.documentSelector, new CodeActionProvider(this), undefined));
this.disposables.push(vscode.languages.registerCallHierarchyProvider(util.documentSelector, new CallHierarchyProvider(this)));
// Because formatting and codeFolding can vary per folder, we need to register these providers once
// and leave them registered. The decision of whether to provide results needs to be made on a per folder basis,
// within the providers themselves.
this.documentFormattingProviderDisposable = vscode.languages.registerDocumentFormattingEditProvider(util.documentSelector, new DocumentFormattingEditProvider(this));
this.formattingRangeProviderDisposable = vscode.languages.registerDocumentRangeFormattingEditProvider(util.documentSelector, new DocumentRangeFormattingEditProvider(this));
this.onTypeFormattingProviderDisposable = vscode.languages.registerOnTypeFormattingEditProvider(util.documentSelector, new OnTypeFormattingEditProvider(this), ";", "}", "\n");
this.codeFoldingProvider = new FoldingRangeProvider(this);
this.codeFoldingProviderDisposable = vscode.languages.registerFoldingRangeProvider(util.documentSelector, this.codeFoldingProvider);
const settings: CppSettings = new CppSettings();
if (settings.enhancedColorization && semanticTokensLegend) {
this.semanticTokensProvider = new SemanticTokensProvider(this);
this.semanticTokensProviderDisposable = vscode.languages.registerDocumentSemanticTokensProvider(util.documentSelector, this.semanticTokensProvider, semanticTokensLegend);
}
// Listen for messages from the language server.
this.registerNotifications();
}
// update all client configurations
this.configuration.setupConfigurations();
initializedClientCount++;
// count number of clients, once all clients are configured, check for trusted compiler to display notification to user and add a short delay to account for config provider logic to finish
if ((vscode.workspace.workspaceFolders === undefined) || (initializedClientCount >= vscode.workspace.workspaceFolders.length)) {
// Timeout waiting for compile_commands.json and config providers.
// The quick pick options will update if they're added later on.
clients.forEach(client => {
if (client instanceof DefaultClient) {
global.setTimeout(() => {
client.configStateReceived.timeout = true;
void client.handleConfigStatusOrPrompt();
}, 15000);
}
});
// The configurations will not be sent to the language server until the default include paths and frameworks have been set.
// The event handlers must be set before this happens.
compilerDefaults = await this.requestCompiler();
DefaultClient.updateClientConfigurations();
clients.forEach(client => {
if (client instanceof DefaultClient) {
client.configStateReceived.compilers = true;
void client.handleConfigStatusOrPrompt();
}
});
}
} catch (err) {
this.isSupported = false; // Running on an OS we don't support yet.
if (!failureMessageShown) {
failureMessageShown = true;
void vscode.window.showErrorMessage(localize("unable.to.start", "Unable to start the C/C++ language server. IntelliSense features will be disabled. Error: {0}", String(err)));
}
}
DefaultClient.isStarted.resolve();
}
private getWorkspaceFolderSettings(workspaceFolderUri: vscode.Uri | undefined, settings: CppSettings, otherSettings: OtherSettings): WorkspaceFolderSettingsParams {
const result: WorkspaceFolderSettingsParams = {
uri: workspaceFolderUri?.toString(),
@@ -1640,7 +1659,7 @@ export class DefaultClient implements Client {
}
}
// TODO: should I set the output channel? Does this sort output between servers?
// TODO: should I set the output channel? Does this sort output between servers?
};
// Create the language client
@@ -1980,123 +1999,129 @@ export class DefaultClient implements Client {
return;
}
telemetry.logLanguageServerEvent('provideCustomConfiguration', { providerId });
void this.provideCustomConfigurationAsync(docUri, requestFile, replaceExisting, onFinished, provider);
}
return this.queueBlockingTask(async () => {
const tokenSource: vscode.CancellationTokenSource = new vscode.CancellationTokenSource();
console.log("provideCustomConfiguration");
private async provideCustomConfigurationAsync(docUri: vscode.Uri, requestFile: string | undefined, replaceExisting: boolean | undefined, onFinished: () => void, provider: CustomConfigurationProvider1) {
DefaultClient.isStarted.reset();
const providerName: string = provider.name;
const tokenSource: vscode.CancellationTokenSource = new vscode.CancellationTokenSource();
console.log("provideCustomConfiguration");
const params: QueryTranslationUnitSourceParams = {
uri: docUri.toString(),
ignoreExisting: !!replaceExisting,
workspaceFolderUri: this.RootUri?.toString()
};
const response: QueryTranslationUnitSourceResult = await this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params);
if (!response.candidates || response.candidates.length === 0) {
// If we didn't receive any candidates, no configuration is needed.
const params: QueryTranslationUnitSourceParams = {
uri: docUri.toString(),
ignoreExisting: !!replaceExisting,
workspaceFolderUri: this.RootUri?.toString()
};
const response: QueryTranslationUnitSourceResult = await this.languageClient.sendRequest(QueryTranslationUnitSourceRequest, params);
if (!response.candidates || response.candidates.length === 0) {
// If we didn't receive any candidates, no configuration is needed.
onFinished();
DefaultClient.isStarted.resolve();
return;
}
// Need to loop through candidates, to see if we can get a custom configuration from any of them.
// Wrap all lookups in a single task, so we can apply a timeout to the entire duration.
const provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[] | null | undefined> = async () => {
const uris: vscode.Uri[] = [];
for (let i: number = 0; i < response.candidates.length; ++i) {
const candidate: string = response.candidates[i];
const tuUri: vscode.Uri = vscode.Uri.parse(candidate);
try {
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
uris.push(tuUri);
}
} catch (err) {
console.warn("Caught exception from canProvideConfiguration");
}
}
if (!uris.length) {
return [];
}
let configs: util.Mutable<SourceFileConfigurationItem>[] = [];
try {
configs = await provider.provideConfigurations(uris, tokenSource.token);
} catch (err) {
console.warn("Caught exception from provideConfigurations");
}
if (configs && configs.length > 0 && configs[0]) {
const fileConfiguration: configs.Configuration | undefined = this.configuration.CurrentConfiguration;
if (fileConfiguration?.mergeConfigurations) {
configs.forEach(config => {
if (fileConfiguration.includePath) {
fileConfiguration.includePath.forEach(p => {
if (!config.configuration.includePath.includes(p)) {
config.configuration.includePath.push(p);
}
});
}
if (fileConfiguration.defines) {
fileConfiguration.defines.forEach(d => {
if (!config.configuration.defines.includes(d)) {
config.configuration.defines.push(d);
}
});
}
if (!config.configuration.forcedInclude) {
config.configuration.forcedInclude = [];
}
if (fileConfiguration.forcedInclude) {
fileConfiguration.forcedInclude.forEach(i => {
if (config.configuration.forcedInclude) {
if (!config.configuration.forcedInclude.includes(i)) {
config.configuration.forcedInclude.push(i);
}
}
});
}
});
}
return configs as SourceFileConfigurationItem[];
}
if (tokenSource.token.isCancellationRequested) {
return null;
}
};
try {
const configs: SourceFileConfigurationItem[] | null | undefined = await this.callTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource);
if (configs && configs.length > 0) {
this.sendCustomConfigurations(configs, provider.version);
}
onFinished();
} catch (err) {
if (requestFile) {
onFinished();
return;
}
// Need to loop through candidates, to see if we can get a custom configuration from any of them.
// Wrap all lookups in a single task, so we can apply a timeout to the entire duration.
const provideConfigurationAsync: () => Thenable<SourceFileConfigurationItem[] | null | undefined> = async () => {
const uris: vscode.Uri[] = [];
for (let i: number = 0; i < response.candidates.length; ++i) {
const candidate: string = response.candidates[i];
const tuUri: vscode.Uri = vscode.Uri.parse(candidate);
try {
if (await provider.canProvideConfiguration(tuUri, tokenSource.token)) {
uris.push(tuUri);
}
} catch (err) {
console.warn("Caught exception from canProvideConfiguration");
}
}
if (!uris.length) {
return [];
}
let configs: util.Mutable<SourceFileConfigurationItem>[] = [];
try {
configs = await provider.provideConfigurations(uris, tokenSource.token);
} catch (err) {
console.warn("Caught exception from provideConfigurations");
}
if (configs && configs.length > 0 && configs[0]) {
const fileConfiguration: configs.Configuration | undefined = this.configuration.CurrentConfiguration;
if (fileConfiguration?.mergeConfigurations) {
configs.forEach(config => {
if (fileConfiguration.includePath) {
fileConfiguration.includePath.forEach(p => {
if (!config.configuration.includePath.includes(p)) {
config.configuration.includePath.push(p);
}
});
}
if (fileConfiguration.defines) {
fileConfiguration.defines.forEach(d => {
if (!config.configuration.defines.includes(d)) {
config.configuration.defines.push(d);
}
});
}
if (!config.configuration.forcedInclude) {
config.configuration.forcedInclude = [];
}
if (fileConfiguration.forcedInclude) {
fileConfiguration.forcedInclude.forEach(i => {
if (config.configuration.forcedInclude) {
if (!config.configuration.forcedInclude.includes(i)) {
config.configuration.forcedInclude.push(i);
}
}
});
}
});
}
return configs as SourceFileConfigurationItem[];
}
if (tokenSource.token.isCancellationRequested) {
return null;
}
};
try {
const configs: SourceFileConfigurationItem[] | null | undefined = await this.callTaskWithTimeout(provideConfigurationAsync, configProviderTimeout, tokenSource);
if (configs && configs.length > 0) {
this.sendCustomConfigurations(configs, provider.version);
}
onFinished();
} catch (err) {
if (requestFile) {
onFinished();
const settings: CppSettings = new CppSettings(this.RootUri);
if (settings.configurationWarnings === true && !this.isExternalHeader(docUri) && !vscode.debug.activeDebugSession) {
const dismiss: string = localize("dismiss.button", "Dismiss");
const disable: string = localize("diable.warnings.button", "Disable Warnings");
const configName: string | undefined = this.configuration.CurrentConfiguration?.name;
if (!configName) {
return;
}
const settings: CppSettings = new CppSettings(this.RootUri);
if (settings.configurationWarnings === true && !this.isExternalHeader(docUri) && !vscode.debug.activeDebugSession) {
const dismiss: string = localize("dismiss.button", "Dismiss");
const disable: string = localize("diable.warnings.button", "Disable Warnings");
const configName: string | undefined = this.configuration.CurrentConfiguration?.name;
if (!configName) {
return;
}
let message: string = localize("unable.to.provide.configuration",
"{0} is unable to provide IntelliSense configuration information for '{1}'. Settings from the '{2}' configuration will be used instead.",
providerName, docUri.fsPath, configName);
if (err) {
message += ` (${err})`;
}
let message: string = localize("unable.to.provide.configuration",
"{0} is unable to provide IntelliSense configuration information for '{1}'. Settings from the '{2}' configuration will be used instead.",
provider.name, docUri.fsPath, configName);
if (err) {
message += ` (${err})`;
}
if (await vscode.window.showInformationMessage(message, dismiss, disable) === disable) {
settings.toggleSetting("configurationWarnings", "enabled", "disabled");
}
if (await vscode.window.showInformationMessage(message, dismiss, disable) === disable) {
settings.toggleSetting("configurationWarnings", "enabled", "disabled");
}
}
});
} finally {
DefaultClient.isStarted.resolve();
}
}
private async handleRequestCustomConfig(requestFile: string): Promise<void> {
@@ -2115,13 +2140,13 @@ export class DefaultClient implements Client {
public async getCurrentConfigCustomVariable(variableName: string): Promise<string> {
await this.ready;
return this.configuration.CurrentConfiguration?.customConfigurationVariables?.[variableName] || '';
return this.configuration.CurrentConfiguration?.customConfigurationVariables?.[variableName] ?? '';
}
public async setCurrentConfigName(configurationName: string): Promise<void> {
await this.ready;
const configurations: configs.Configuration[] = this.configuration.Configurations || [];
const configurations: configs.Configuration[] = this.configuration.Configurations ?? [];
const configurationIndex: number = configurations.findIndex((config) => config.name === configurationName);
if (configurationIndex === -1) {
@@ -2163,8 +2188,7 @@ export class DefaultClient implements Client {
public async takeOwnership(document: vscode.TextDocument): Promise<void> {
this.trackedDocuments.add(document);
this.updateActiveDocumentTextOptions();
await this.ready;
return this.sendDidOpen(document);
await this.sendDidOpen(document);
}
public async sendDidOpen(document: vscode.TextDocument): Promise<void> {
@@ -2180,24 +2204,82 @@ export class DefaultClient implements Client {
}
/**
* returns a promise that waits for the all pendingTasks are complete (e.g. language client is ready for use)
* a Promise that can be awaited to know when it's ok to proceed.
*
* This is a lighter-weight complement to `enqueue()`
*
* Use `await <client>.ready` when you need to ensure that the client is initialized, and to run in order
* Use `enqueue()` when you want to ensure that subsequent calls are blocked until a critical bit of code is run.
*
* This is lightweight, because if the queue is empty, then the only thing to wait for is the client itself to be initialized
*/
get ready(): Promise<void> {
return this.isSupported ? Promise.resolve(pendingTask?.getPromise() || undefined) : fail(localize("unsupported.client", "Unsupported client"));
if (!DefaultClient.dispatching.isCompleted || DefaultClient.queue.length) {
// if the dispatcher has stuff going on, then we need to stick in a promise into the queue so we can
// be notified when it's our turn
const p = new ManualPromise<void>();
DefaultClient.queue.push([p as ManualPromise<unknown>]);
return p;
}
// otherwise, we're only waiting for the client to be in an initialized state, in which case just wait for that.
return DefaultClient.isStarted;
}
/**
* Queue a task that blocks all future tasks until it completes. This is currently only intended to be used
* during language client startup and for custom configuration providers.
* @param task The task that blocks all future tasks
* Enqueue a task to ensure that the order is maintained. The tasks are executed sequentially after the client is ready.
*
* this is a bit more expensive than `.ready` - this ensures the task is absolutely finished executing before allowing
* the dispatcher to move forward.
*
* Use `enqueue()` when you want to ensure that subsequent calls are blocked until a critical bit of code is run.
* Use `await <client>.ready` when you need to ensure that the client is initialized, and still run in order.
*/
private async queueBlockingTask<T>(task: () => Thenable<T>): Promise<T> {
if (this.isSupported) {
pendingTask = new util.BlockingTask<T>(task, pendingTask);
return pendingTask.getPromise();
} else {
throw new Error(localize("unsupported.client", "Unsupported client"));
enqueue<T>(task: () => Promise<T>) {
ok(this.isSupported, localize("unsupported.client", "Unsupported client"));
// create a placeholder promise that is resolved when the task is complete.
const result = new ManualPromise<unknown>();
// add the task to the queue
DefaultClient.queue.push([result, task]);
// if we're not already dispatching, start
if (DefaultClient.dispatching.isSet) {
// start dispatching
void DefaultClient.dispatch();
}
// return the placeholder promise to the caller.
return result as Promise<T>;
}
/**
* The dispatch loop asynchronously processes items in the async queue in order, and ensures that tasks are dispatched in the
* order they were inserted.
*/
private static async dispatch() {
// ensure that this is OK to start working
await this.isStarted;
// reset the promise for the dispatcher
DefaultClient.dispatching.reset();
do {
// pick items up off the queue and run then one at a time until the queue is empty
const [promise, task] = DefaultClient.queue.shift() ?? [];
if (promise) {
try {
promise.resolve(task ? await task() : undefined);
} catch (e) {
console.log(e);
promise.reject(e);
}
}
} while (DefaultClient.queue.length);
// unblock anything that is waiting for the dispatcher to empty
this.dispatching.resolve();
}
private callTaskWithTimeout<T>(task: () => Thenable<T>, ms: number, cancelToken?: vscode.CancellationTokenSource): Promise<T> {
@@ -2732,8 +2814,7 @@ export class DefaultClient implements Client {
switchHeaderSourceFileName: fileName,
workspaceFolderUri: rootUri.toString()
};
await this.ready;
return this.languageClient.sendRequest(SwitchHeaderSourceRequest, params);
return this.enqueue(async () => this.languageClient.sendRequest(SwitchHeaderSourceRequest, params));
}
public async requestCompiler(newCompilerPath?: string): Promise<configs.CompilerDefaults> {
@@ -3495,7 +3576,7 @@ export class DefaultClient implements Client {
if (lastEdit && lastEdit.newText.includes("#include") && lastEdit.range.isEqual(range)) {
// Destination file is empty.
// The edit positions for #include header file and definition or declaration are the same.
selectionPositionAdjustment = (lastEdit.newText.match(/\n/g) || []).length;
selectionPositionAdjustment = (lastEdit.newText.match(/\n/g) ?? []).length;
}
lastEdit = new vscode.TextEdit(range, edit.newText);
const position: vscode.Position = new vscode.Position(edit.range.start.line, edit.range.start.character);
@@ -3513,7 +3594,7 @@ export class DefaultClient implements Client {
// Move the cursor to the new declaration/definition edit, accounting for \n or \n\n at the start.
let startLine: number = lastEdit.range.start.line;
let numNewlines: number = (lastEdit.newText.match(/\n/g) || []).length;
let numNewlines: number = (lastEdit.newText.match(/\n/g) ?? []).length;
if (lastEdit.newText.startsWith("\r\n\r\n") || lastEdit.newText.startsWith("\n\n")) {
startLine += 2;
numNewlines -= 2;
@@ -3664,6 +3745,10 @@ class NullClient implements Client {
private referencesCommandModeEvent = new vscode.EventEmitter<refs.ReferencesCommandMode>();
readonly ready: Promise<void> = Promise.resolve();
async enqueue<T>(task: () => Promise<T>) {
return task();
}
public get InitializingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
public get IndexingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
public get ParsingWorkspaceChanged(): vscode.Event<boolean> { return this.booleanEvent.event; }
+2 -2
View File
@@ -368,6 +368,7 @@ export async function processDelayedDidOpen(document: vscode.TextDocument): Prom
}
await client.provideCustomConfiguration(document.uri, undefined);
// client.takeOwnership() will call client.TrackedDocuments.add() again, but that's ok. It's a Set.
client.onDidOpenTextDocument(document);
await client.takeOwnership(document);
return true;
}
@@ -382,8 +383,7 @@ function onDidChangeVisibleTextEditors(editors: readonly vscode.TextEditor[]): v
editors.forEach(async (editor) => {
if (util.isCpp(editor.document)) {
const client: Client = clients.getClientFor(editor.document.uri);
await client.ready;
await processDelayedDidOpen(editor.document);
await client.enqueue(() => processDelayedDidOpen(editor.document));
client.onDidChangeVisibleTextEditor(editor);
}
});
+11 -16
View File
@@ -12,10 +12,10 @@ import { clients, onDidChangeActiveTextEditor, processDelayedDidOpen } from './e
export function createProtocolFilter(): Middleware {
// Disabling lint for invoke handlers
const invoke1 = (a: any, next: (a: any) => any): any => clients.ActiveClient.ready.then(() => next(a));
const invoke2 = (a: any, b: any, next: (a: any, b: any) => any): any => clients.ActiveClient.ready.then(() => next(a, b));
const invoke3 = (a: any, b: any, c: any, next: (a: any, b: any, c: any) => any): any => clients.ActiveClient.ready.then(() => next(a, b, c));
const invoke4 = (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any): any => clients.ActiveClient.ready.then(() => next(a, b, c, d));
const invoke1 = (a: any, next: (a: any) => any): any => clients.ActiveClient.enqueue(() => next(a));
const invoke2 = (a: any, b: any, next: (a: any, b: any) => any): any => clients.ActiveClient.enqueue(() => next(a, b));
const invoke3 = (a: any, b: any, c: any, next: (a: any, b: any, c: any) => any): any => clients.ActiveClient.enqueue(() => next(a, b, c));
const invoke4 = (a: any, b: any, c: any, d: any, next: (a: any, b: any, c: any, d: any) => any): any => clients.ActiveClient.enqueue(() => next(a, b, c, d));
return {
didOpen: async (document, _sendMessage) => {
@@ -27,8 +27,7 @@ export function createProtocolFilter(): Middleware {
// If the file was visible editor when we were activated, we will not get a call to
// onDidChangeVisibleTextEditors, so immediately open any file that is visible when we receive didOpen.
// Otherwise, we defer opening the file until it's actually visible.
await clients.ActiveClient.ready;
await processDelayedDidOpen(document);
await clients.ActiveClient.enqueue(() => processDelayedDidOpen(document));
if (editor && editor === vscode.window.activeTextEditor) {
onDidChangeActiveTextEditor(editor);
}
@@ -42,12 +41,11 @@ export function createProtocolFilter(): Middleware {
// didOpen), and first becomes visible.
}
},
didChange: async (textDocumentChangeEvent, sendMessage) => {
await clients.ActiveClient.ready;
didChange: async (textDocumentChangeEvent, sendMessage) => clients.ActiveClient.enqueue(async () => {
const me: Client = clients.getClientFor(textDocumentChangeEvent.document.uri);
me.onDidChangeTextDocument(textDocumentChangeEvent);
await sendMessage(textDocumentChangeEvent);
},
}),
willSave: invoke1,
willSaveWaitUntil: async (event, sendMessage) => {
// await clients.ActiveClient.ready;
@@ -60,26 +58,23 @@ export function createProtocolFilter(): Middleware {
return [];
},
didSave: invoke1,
didClose: async (document, sendMessage) => {
await clients.ActiveClient.ready;
didClose: async (document, sendMessage) => clients.ActiveClient.enqueue(async () => {
const me: Client = clients.getClientFor(document.uri);
if (me.TrackedDocuments.has(document)) {
me.onDidCloseTextDocument(document);
me.TrackedDocuments.delete(document);
await sendMessage(document);
}
},
}),
provideCompletionItem: invoke4,
resolveCompletionItem: invoke2,
provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => {
await clients.ActiveClient.ready;
provideHover: async (document, position, token, next: (document: any, position: any, token: any) => any) => clients.ActiveClient.enqueue(async () => {
const me: Client = clients.getClientFor(document.uri);
if (me.TrackedDocuments.has(document)) {
return next(document, position, token);
}
return null;
},
}),
provideSignatureHelp: invoke4,
provideDefinition: invoke3,
provideReferences: invoke4,
+1 -1
View File
@@ -8,7 +8,7 @@ import * as path from 'path';
import * as vscode from 'vscode';
import * as nls from 'vscode-nls';
import { CppSettings } from '../LanguageServer/settings';
import { ManualPromise } from '../Utility/Async/manual-promise';
import { ManualPromise } from '../Utility/Async/manualPromise';
import { ISshHostInfo, ProcessReturnType, splitLines, stripEscapeSequences } from '../common';
import { isWindows } from '../constants';
import { getSshChannel } from '../logger';
@@ -47,7 +47,7 @@ export class ManualPromise<T = void> implements Promise<T> {
};
/**
* A method to manually reject the Promise
* A method to manually reject the Promise
*/
public reject: (e: any) => void = (e) => {
void e; /* */
@@ -3,7 +3,7 @@
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { ManualPromise } from './manual-promise';
import { ManualPromise } from './manualPromise';
import { Resetable } from './resolvable';
/**
@@ -18,9 +18,11 @@ export class ManualSignal<T> implements Promise<T>, Resetable<T> {
[Symbol.toStringTag] = 'Promise';
private promise = new ManualPromise<T>();
constructor() {
// initially not reset.
this.promise.resolve();
constructor(initiallyReset = false) {
if (!initiallyReset) {
// initially not reset.
this.promise.resolve();
}
}
get isPending(): boolean {
return this.promise.isPending;
@@ -34,6 +36,12 @@ export class ManualSignal<T> implements Promise<T>, Resetable<T> {
get isRejected(): boolean {
return this.promise.isRejected;
}
get isSet(): boolean {
return this.promise.isCompleted;
}
get isReset(): boolean {
return !this.promise.isCompleted;
}
/**
* Attaches callbacks for the resolution and/or rejection of the Promise.
* @param onfulfilled The callback to execute when the Promise is resolved.
@@ -70,22 +78,26 @@ export class ManualSignal<T> implements Promise<T>, Resetable<T> {
* @param value
*/
resolve(value: T): Resetable<T> {
this.promise.resolve(value);
if (!this.promise.isCompleted) {
this.promise.resolve(value);
}
return this as unknown as Resetable<T>;
}
/**
* A method to manually reject the Promise.
*
* This doesn't reset this instance to a new promise interally, call 'reset' to do that.
* This doesn't reset this instance to a new promise interally, call 'reset' to do that.
* @param value
*/
reject(reason: any): Resetable<T> {
this.promise.reject(reason);
if (!this.promise.isCompleted) {
this.promise.reject(reason);
}
return this as unknown as Resetable<T>;
}
/** Manually reset the promise to an uncompleted state. */
/** Manually reset the promise to an uncompleted state. */
reset(): Resetable<T> {
if (this.promise.isCompleted) {
this.promise = new ManualPromise<T>();
+1 -1
View File
@@ -3,7 +3,7 @@
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { ManualPromise } from './manual-promise';
import { ManualPromise } from './manualPromise';
import { Resolveable } from './resolvable';
/**
+11 -3
View File
@@ -3,10 +3,18 @@
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { fail } from 'node:assert';
import { returns } from './returns';
import { sleep } from './sleep';
/** wait on any of the promises to resolve, or the timeout to expire */
/** wait on any of the promises to resolve, or if the timeout is reached, throw */
export async function timeout(msecs: number, ...promises: Promise<any>[]): Promise<any> {
// get a promise for the timeout
const t = sleep(msecs).then(() => fail(`Timeout expired after ${msecs}ms`));
export function timeout(msecs: number, ...promises: Promise<any>[]): Promise<any> {
return Promise.any([sleep(msecs), ...promises]);
// wait until either the timout expires or one of the promises resolves
await Promise.race([t, ...promises]);
// tag the timeout with a catch to prevent unhandled rejection
t.catch(returns.undefined);
}
+1 -32
View File
@@ -15,7 +15,7 @@ import { DocumentFilter } from 'vscode-languageclient';
import * as nls from 'vscode-nls';
import { TargetPopulation } from 'vscode-tas-client';
import * as which from "which";
import { ManualPromise } from './Utility/Async/manual-promise';
import { ManualPromise } from './Utility/Async/manualPromise';
import { isWindows } from './constants';
import { getOutputChannelLogger, showOutputChannel } from './logger';
import { PlatformInformation } from './platform';
@@ -1172,37 +1172,6 @@ export function escapeForSquiggles(s: string): string {
return newResults;
}
export class BlockingTask<T> {
private done: boolean = false;
private promise: Thenable<T>;
constructor(task: () => Thenable<T>, dependency?: BlockingTask<any>) {
if (!dependency) {
this.promise = task();
} else {
this.promise = new Promise<T>((resolve, reject) => {
const f1: () => void = () => {
task().then(resolve, reject);
};
const f2: (err: any) => void = (err) => {
console.log(err);
task().then(resolve, reject);
};
dependency.promise.then(f1, f2);
});
}
this.promise.then(() => this.done = true, () => this.done = true);
}
public get Done(): boolean {
return this.done;
}
public getPromise(): Thenable<T> {
return this.promise;
}
}
export function getSenderType(sender?: any): string {
if (isString(sender)) {
return sender;
+8 -1
View File
@@ -4,32 +4,39 @@
* ------------------------------------------------------------------------------------------ */
'use strict';
import { ok } from 'assert';
import * as vscode from 'vscode';
import { CppToolsTestHook, IntelliSenseStatus, Status } from 'vscode-cpptools/out/testApi';
export class TestHook implements CppToolsTestHook {
private disposed = false;
private intelliSenseStatusChangedEvent: vscode.EventEmitter<IntelliSenseStatus> = new vscode.EventEmitter<IntelliSenseStatus>();
private statusChangedEvent: vscode.EventEmitter<Status> = new vscode.EventEmitter<Status>();
// The StatusChanged event is deprecated in CppToolsTestHook API.
public get StatusChanged(): vscode.Event<Status> {
ok(!this.disposed, "TestHook is disposed.");
return this.statusChangedEvent.event;
}
public get IntelliSenseStatusChanged(): vscode.Event<IntelliSenseStatus> {
ok(!this.disposed, "TestHook is disposed.");
return this.intelliSenseStatusChangedEvent.event;
}
public get valid(): boolean {
return !!this.intelliSenseStatusChangedEvent && !!this.statusChangedEvent;
return !this.disposed && !!this.intelliSenseStatusChangedEvent && !!this.statusChangedEvent;
}
public updateStatus(status: IntelliSenseStatus): void {
ok(!this.disposed, "TestHook is disposed.");
this.intelliSenseStatusChangedEvent.fire(status);
this.statusChangedEvent.fire(status.status);
}
public dispose(): void {
ok(!this.disposed, "TestHook is disposed.");
this.disposed = true;
this.intelliSenseStatusChangedEvent.dispose();
this.statusChangedEvent.dispose();
}
@@ -2,6 +2,12 @@
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/triple-slash-reference */
/* eslint-disable @typescript-eslint/no-non-null-assertion */
/// <reference path="../../../vscode.d.ts" />
import * as assert from 'assert';
import * as vscode from 'vscode';
import * as api from 'vscode-cpptools';
@@ -28,37 +34,25 @@ suite("[Inlay hints test]", function(): void {
let referenceOperatorEnabledValue: any;
let referenceOperatorShowSpaceValue: any;
// Test setup
const rootUri: vscode.Uri = vscode.workspace.workspaceFolders[1].uri;
const wf = vscode.workspace.workspaceFolders?.[1] ?? assert.fail("Test failed because workspace folder is undefined.");
const rootUri: vscode.Uri = wf.uri;
const filePath: string | undefined = rootUri.fsPath + "/inlay_hints.cpp";
const fileUri: vscode.Uri = vscode.Uri.file(filePath);
const disposables: vscode.Disposable[] = [];
let getIntelliSenseStatus: any;
suiteSetup(async function(): Promise<void> {
await testHelpers.activateCppExtension();
const cpptools = await apit.getCppToolsTestApi(api.Version.latest);
if (!cpptools) {
return;
}
const cpptools = await apit.getCppToolsTestApi(api.Version.latest) ?? assert.fail("Could not get cpptools test api");
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
disposables.push(testHook);
getIntelliSenseStatus = new Promise<void>((resolve, reject) => {
disposables.push(testHook.IntelliSenseStatusChanged(result => {
result = result as apit.IntelliSenseStatus;
if (result.filename === "inlay_hints.cpp" && result.status === apit.Status.IntelliSenseReady) {
resolve();
}
}));
setTimeout(() => { reject(new Error("Timeout: IntelliSenseStatusChanged event")); }, testHelpers.defaultTimeout);
});
// Start language server
console.log("Open file: " + fileUri.toString());
const document: vscode.TextDocument = await vscode.workspace.openTextDocument(fileUri);
await vscode.window.showTextDocument(document);
await getIntelliSenseStatus;
saveOriginalSettings();
await useDefaultSettings();
});
@@ -69,13 +63,13 @@ suite("[Inlay hints test]", function(): void {
});
function saveOriginalSettings(): void {
autoDeclarationTypesEnabledValue = inlayHintSettings.inspect(autoDeclarationTypesEnabled).globalValue;
autoDeclarationTypesShowOnLeftValue = inlayHintSettings.inspect(autoDeclarationTypesShowOnLeft).globalValue;
parameterNamesEnabledValue = inlayHintSettings.inspect(parameterNamesEnabled).globalValue;
parameterNamesSuppressValue = inlayHintSettings.inspect(parameterNamesSuppress).globalValue;
parameterNamesHideUnderScoreValue = inlayHintSettings.inspect(parameterNamesHideUnderScore).globalValue;
referenceOperatorEnabledValue = inlayHintSettings.inspect(referenceOperatorEnabled).globalValue;
referenceOperatorShowSpaceValue = inlayHintSettings.inspect(referenceOperatorShowSpace).globalValue;
autoDeclarationTypesEnabledValue = inlayHintSettings.inspect(autoDeclarationTypesEnabled)!.globalValue;
autoDeclarationTypesShowOnLeftValue = inlayHintSettings.inspect(autoDeclarationTypesShowOnLeft)!.globalValue;
parameterNamesEnabledValue = inlayHintSettings.inspect(parameterNamesEnabled)!.globalValue;
parameterNamesSuppressValue = inlayHintSettings.inspect(parameterNamesSuppress)!.globalValue;
parameterNamesHideUnderScoreValue = inlayHintSettings.inspect(parameterNamesHideUnderScore)!.globalValue;
referenceOperatorEnabledValue = inlayHintSettings.inspect(referenceOperatorEnabled)!.globalValue;
referenceOperatorShowSpaceValue = inlayHintSettings.inspect(referenceOperatorShowSpace)!.globalValue;
}
async function restoreOriginalSettings(): Promise<void> {
@@ -103,12 +97,12 @@ suite("[Inlay hints test]", function(): void {
await changeInlayHintSetting(autoDeclarationTypesEnabled, disabled);
await changeInlayHintSetting(autoDeclarationTypesShowOnLeft, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 0, "Incorrect number of results.");
await changeInlayHintSetting(autoDeclarationTypesEnabled, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 12, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Type;
@@ -125,19 +119,17 @@ suite("[Inlay hints test]", function(): void {
assertHintValues(result2, 10, 28, 14, ": int", expectedKind);
assertHintValues(result2, 11, 29, 15, ": int", expectedKind);
});
test("[Inlay Hints - auto type, show on left]", async () => {
const range: vscode.Range = new vscode.Range(new vscode.Position(15, 0), new vscode.Position(31, 0));
await changeInlayHintSetting(autoDeclarationTypesEnabled, disabled);
await changeInlayHintSetting(autoDeclarationTypesShowOnLeft, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 0, "Incorrect number of results.");
await changeInlayHintSetting(autoDeclarationTypesEnabled, enabled);
await changeInlayHintSetting(autoDeclarationTypesShowOnLeft, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 12, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Type;
@@ -160,13 +152,11 @@ suite("[Inlay hints test]", function(): void {
await changeInlayHintSetting(parameterNamesEnabled, disabled);
await changeInlayHintSetting(referenceOperatorEnabled, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 0, "Incorrect number of results.");
await changeInlayHintSetting(parameterNamesEnabled, enabled);
await changeInlayHintSetting(parameterNamesSuppress, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 16, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Parameter;
@@ -193,7 +183,6 @@ suite("[Inlay hints test]", function(): void {
await changeInlayHintSetting(parameterNamesEnabled, enabled);
await changeInlayHintSetting(parameterNamesHideUnderScore, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 4, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Parameter;
@@ -203,7 +192,6 @@ suite("[Inlay hints test]", function(): void {
assertHintValues(result1, 3, 35, 25, "a:", expectedKind);
await changeInlayHintSetting(parameterNamesHideUnderScore, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 4, "Incorrect number of results.");
assertHintValues(result2, 0, 35, 16, "x:", expectedKind);
@@ -218,12 +206,10 @@ suite("[Inlay hints test]", function(): void {
await changeInlayHintSetting(parameterNamesEnabled, disabled);
await changeInlayHintSetting(referenceOperatorEnabled, disabled);
await changeInlayHintSetting(referenceOperatorShowSpace, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 0, "Incorrect number of results.");
await changeInlayHintSetting(referenceOperatorEnabled, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 16, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Parameter;
@@ -254,7 +240,6 @@ suite("[Inlay hints test]", function(): void {
await changeInlayHintSetting(parameterNamesSuppress, disabled);
await changeInlayHintSetting(referenceOperatorEnabled, enabled);
await changeInlayHintSetting(referenceOperatorShowSpace, disabled);
await getIntelliSenseStatus;
const result1 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result1.length, 12, "Incorrect number of results.");
const expectedKind = vscode.InlayHintKind.Parameter;
@@ -272,7 +257,6 @@ suite("[Inlay hints test]", function(): void {
assertHintValues(result1, 11, 95, 9, "flag:", expectedKind);
await changeInlayHintSetting(referenceOperatorShowSpace, enabled);
await getIntelliSenseStatus;
const result2 = await vscode.commands.executeCommand<vscode.InlayHint[]>('vscode.executeInlayHintProvider', fileUri, range);
assert.strictEqual(result2.length, 12, "Incorrect number of results.");
assertHintValues(result2, 0, 87, 9, "& first:", expectedKind);
@@ -290,10 +274,10 @@ suite("[Inlay hints test]", function(): void {
});
async function changeInlayHintSetting(inlayHintSetting: string, valueNew: any): Promise<void> {
const valueBeforeChange: any = inlayHintSettings.inspect(inlayHintSetting).globalValue;
const valueBeforeChange: any = inlayHintSettings.inspect(inlayHintSetting)!.globalValue;
if (valueBeforeChange !== valueNew) {
await inlayHintSettings.update(inlayHintSetting, valueNew, vscode.ConfigurationTarget.Global);
const valueAfterChange: any = inlayHintSettings.inspect(inlayHintSetting).globalValue;
const valueAfterChange: any = inlayHintSettings.inspect(inlayHintSetting)!.globalValue;
assert.strictEqual(valueAfterChange, valueNew, `Unable to change setting: ${inlayHintSetting}`);
}
}
@@ -7,6 +7,8 @@ import * as os from 'os';
import * as vscode from 'vscode';
import * as api from 'vscode-cpptools';
import * as apit from 'vscode-cpptools/out/testApi';
import { ManualSignal } from '../../../src/Utility/Async/manualSignal';
import { timeout } from '../../../src/Utility/Async/timeout';
import * as testHelpers from '../testHelpers';
suite("[Quick info test]", function(): void {
@@ -15,29 +17,26 @@ suite("[Quick info test]", function(): void {
const filePath: string = `${vscode.workspace.workspaceFolders?.[1]?.uri.fsPath}/quickInfo.cpp`;
const fileUri: vscode.Uri = vscode.Uri.file(filePath);
let platform: string = "";
const getIntelliSenseStatus = new ManualSignal<void>();
suiteSetup(async function(): Promise<void> {
await testHelpers.activateCppExtension();
cpptools = await apit.getCppToolsTestApi(api.Version.latest);
cpptools = await apit.getCppToolsTestApi(api.Version.latest) ?? assert.fail("Could not get CppToolsTestApi");
platform = os.platform();
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
disposables.push(testHook);
const getIntelliSenseStatus: any = new Promise<void>((resolve, reject) => {
disposables.push(testHook.IntelliSenseStatusChanged(result => {
result = result as apit.IntelliSenseStatus;
if (result.filename === "quickInfo.cpp" && result.status === apit.Status.IntelliSenseReady) {
resolve();
}
}));
setTimeout(() => { reject(new Error("Timeout: IntelliSenseStatusChanged event")); }, testHelpers.defaultTimeout);
testHook.IntelliSenseStatusChanged((result: apit.IntelliSenseStatus) => {
if (result.filename === "quickInfo.cpp" && result.status === apit.Status.IntelliSenseReady) {
getIntelliSenseStatus.resolve();
}
});
// Start language server
console.log("Open file: " + fileUri.toString());
await vscode.commands.executeCommand("vscode.open", fileUri);
await getIntelliSenseStatus;
await timeout(5000, getIntelliSenseStatus.then(() => getIntelliSenseStatus.reset()));
});
suiteTeardown(function(): void {
@@ -53,11 +52,12 @@ suite("[Quick info test]", function(): void {
expectedMap.set("darwin", expected_full_comment);
const actual: string = (<vscode.MarkdownString>result[0].contents[0]).value;
const expected: string = expectedMap.get(platform);
const expected: string = expectedMap.get(platform) ?? assert.fail("Platform not found");
assert.strictEqual(actual, expected);
});
test("[Hover over function call - Doxygen comment]", async () => {
// [TODO] - temporarily skip this test at the moment - it doesn't currently work (locally anyway) --
test.skip("[Hover over function call - Doxygen comment]", async () => {
const result: vscode.Hover[] = <vscode.Hover[]>(await vscode.commands.executeCommand('vscode.executeHoverProvider', fileUri, new vscode.Position(36, 9)));
const expected_full_comment: string = `\`\`\`cpp\nint testDoxygen<int>(int base, int height)\n\`\`\` \nCalculates area of rectangle \n \n**Template Parameters:** \n\`T\` is template param \n \n**Parameters:** \n\`base\` is horizontal length \n\`height\` is vertical length \n \n**Returns:** \nArea of rectangle \n \n**Exceptions:** \nThis is an exception comment`;
@@ -67,7 +67,7 @@ suite("[Quick info test]", function(): void {
expectedMap.set("darwin", expected_full_comment);
const actual: string = (<vscode.MarkdownString>result[0].contents[0]).value;
const expected: string = expectedMap.get(platform);
const expected: string = expectedMap.get(platform) ?? assert.fail("Platform not found");
assert.strictEqual(actual, expected);
});
@@ -79,7 +79,7 @@ suite("[Quick info test]", function(): void {
expectedMap.set("linux", `\`\`\`cpp\nstd::string stringVar\n\`\`\``);
expectedMap.set("darwin", `\`\`\`cpp\nstd::__cxx11::string stringVar\n\`\`\``);
const expected: string = expectedMap.get(platform);
const expected: string = expectedMap.get(platform) ?? assert.fail("Platform not found");
const actual: string = (<vscode.MarkdownString>result[0].contents[0]).value;
assert.strictEqual(actual, expected);
});
@@ -6,38 +6,39 @@ import * as assert from 'assert';
import * as vscode from 'vscode';
import * as api from 'vscode-cpptools';
import * as apit from 'vscode-cpptools/out/testApi';
import { ManualSignal } from '../../../src/Utility/Async/manualSignal';
import { timeout } from '../../../src/Utility/Async/timeout';
import * as testHelpers from '../testHelpers';
suite(`[Reference test]`, function(): void {
let cpptools: apit.CppToolsTestApi;
const disposables: vscode.Disposable[] = [];
const path: string = vscode.workspace.workspaceFolders[1].uri.fsPath + "/references.cpp";
const wf = vscode.workspace.workspaceFolders?.[1] ?? assert.fail("Could not get workspace folder");
const path: string = wf.uri.fsPath + "/references.cpp";
const fileUri: vscode.Uri = vscode.Uri.file(path);
let testHook: apit.CppToolsTestHook;
let getIntelliSenseStatus: any;
const getIntelliSenseStatus = new ManualSignal<void>();
let document: vscode.TextDocument;
suiteSetup(async function(): Promise<void> {
await testHelpers.activateCppExtension();
cpptools = await apit.getCppToolsTestApi(api.Version.latest);
cpptools = await apit.getCppToolsTestApi(api.Version.latest) ?? assert.fail("Could not get CppToolsTestApi");
testHook = cpptools.getTestHook();
getIntelliSenseStatus = new Promise<void>((resolve, reject) => {
disposables.push(testHook.IntelliSenseStatusChanged(result => {
result = result as apit.IntelliSenseStatus;
if (result.filename === "references.cpp" && result.status === apit.Status.IntelliSenseReady) {
resolve();
}
}));
setTimeout(() => { reject(new Error("Timeout: IntelliSenseStatusChanged event")); }, testHelpers.defaultTimeout);
testHook.IntelliSenseStatusChanged((result: apit.IntelliSenseStatus) => {
if (result.filename === "references.cpp" && result.status === apit.Status.IntelliSenseReady) {
getIntelliSenseStatus.resolve();
}
});
disposables.push(testHook);
// Start language server
console.log("Open file: " + fileUri.toString());
document = await vscode.workspace.openTextDocument(fileUri);
await vscode.window.showTextDocument(document);
await getIntelliSenseStatus;
await timeout(5000, getIntelliSenseStatus.then(() => getIntelliSenseStatus.reset()));
});
test("[Find confirmed references of a symbol]", async () => {
@@ -1,35 +1,75 @@
import * as path from 'path';
import { runTests } from '@vscode/test-electron';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../../../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './index');
// Note, when running tests locally, replace TESTS_WORKSPACE with local path to "~/Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace"
// in the Launch.json file.
let testWorkspace: string | undefined = process.env.TESTS_WORKSPACE;
if (!testWorkspace) {
console.error("Unable to read process.env.TESTS_WORKSPACE");
} else {
console.log("TESTS_WORKSPACE: " + testWorkspace);
}
const launchArgs = [ "--disable-extensions", testWorkspace ];
// Download VS Code, unzip it and run the integration test
await runTests({ launchArgs, extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron';
import { ok } from 'assert';
import { createHash } from 'crypto';
import { existsSync } from 'fs';
import { mkdir as md, stat } from 'fs/promises';
import { tmpdir } from 'os';
import { resolve } from 'path';
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = resolve(__dirname, '../../../../');
const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(extensionDevelopmentPath).digest('hex').substring(0,6) );
const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`]
};
async function mkdir(filePath:string) {
filePath = resolve(filePath);
try {
const s = await stat(filePath);
if( s.isDirectory() ) {
return filePath;
}
throw new Error(`Cannot create directory '${filePath}' because thre is a file there.`);
} catch {
// no worries
}
await md(filePath, { recursive: true })
return filePath;
}
async function main() {
try {
// create a folder for the isolated test environment
await mkdir(isolated);
// download VSCode to that location
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...launchArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
// clean up args so that it works with the isolate extensions and data directories
launchArgs.push(`--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`);
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = resolve(__dirname, './index');
// Note, when running tests locally, replace TESTS_WORKSPACE with local path to "~/Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace"
// in the Launch.json file.
let testWorkspace: string | undefined = process.env.TESTS_WORKSPACE || resolve(extensionDevelopmentPath, '../../Vcls-vscode-test/MultirootDeadlockTest/test.code-workspace');
ok(existsSync(testWorkspace), `TESTS_WORKSPACE '${testWorkspace}' does not exist.`);
console.log("TESTS_WORKSPACE: " + testWorkspace);
launchArgs.push("--disable-extensions", testWorkspace );
// Download VS Code, unzip it and run the integration test
await runTests({
...options,
launchArgs,
extensionDevelopmentPath,
extensionTestsPath
});
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
@@ -1,26 +1,65 @@
import * as path from 'path';
import { runTests } from '@vscode/test-electron';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../../../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './index');
const launchArgs = [ "--disable-extensions" ];
// Download VS Code, unzip it and run the integration test
await runTests({ launchArgs, extensionDevelopmentPath, extensionTestsPath });
} catch(err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron';
import { createHash } from 'crypto';
import { mkdir as md, stat } from 'fs/promises';
import { tmpdir } from 'os';
import { resolve } from 'path';
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = resolve(__dirname, '../../../../');
const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(extensionDevelopmentPath).digest('hex').substring(0,6) );
const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`]
};
async function mkdir(filePath:string) {
filePath = resolve(filePath);
try {
const s = await stat(filePath);
if( s.isDirectory() ) {
return filePath;
}
throw new Error(`Cannot create directory '${filePath}' because thre is a file there.`);
} catch {
// no worries
}
await md(filePath, { recursive: true })
return filePath;
}
async function main() {
try {
// create a folder for the isolated test environment
await mkdir(isolated);
// download VSCode to that location
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...launchArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
// clean up args so that it works with the isolate extensions and data directories
launchArgs.push(`--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`);
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = resolve(__dirname, './index');
launchArgs.push("--disable-extensions");
// Download VS Code, unzip it and run the integration test
await runTests({
...options,
launchArgs,
extensionDevelopmentPath,
extensionTestsPath
});
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
@@ -2,13 +2,17 @@
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference path="../../../vscode.d.ts" />
import * as assert from 'assert';
import * as vscode from 'vscode';
import * as api from 'vscode-cpptools';
import * as apit from 'vscode-cpptools/out/testApi';
import * as util from '../../../src/common';
import * as config from '../../../src/LanguageServer/configurations';
import { getLanguageConfigFromPatterns } from '../../../src/LanguageServer/languageConfig';
import * as util from '../../../src/common';
import * as testHelpers from '../testHelpers';
suite("multiline comment setting tests", function(): void {
@@ -52,27 +56,27 @@ suite("multiline comment setting tests", function(): void {
];
test("Check the default OnEnterRules for C", () => {
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('c', [ "/**" ]).onEnterRules;
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('c', [ "/**" ]).onEnterRules ?? assert.fail('onEnterRules is undefined');
assert.deepStrictEqual(rules, defaultMLRules);
});
test("Check for removal of single line comment continuations for C", () => {
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('c', [ "/**", "///" ]).onEnterRules;
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('c', [ "/**", "///" ]).onEnterRules ?? assert.fail('onEnterRules is undefined');
assert.deepStrictEqual(rules, defaultMLRules);
});
test("Check the default OnEnterRules for C++", () => {
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "/**" ]).onEnterRules;
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "/**" ]).onEnterRules ?? assert.fail('onEnterRules is undefined');
assert.deepStrictEqual(rules, defaultMLRules);
});
test("Make sure duplicate rules are removed", () => {
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "/**", { begin: "/**", continue: " * " }, "/**" ]).onEnterRules;
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "/**", { begin: "/**", continue: " * " }, "/**" ]).onEnterRules ?? assert.fail('onEnterRules is undefined');
assert.deepStrictEqual(rules, defaultMLRules);
});
test("Check single line rules for C++", () => {
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "///" ]).onEnterRules;
const rules: vscode.OnEnterRule[] = getLanguageConfigFromPatterns('cpp', [ "///" ]).onEnterRules ?? assert.fail('onEnterRules is undefined');
assert.deepStrictEqual(rules, defaultSLRules);
});
@@ -81,10 +85,11 @@ suite("multiline comment setting tests", function(): void {
/* **************************************************************************** */
function cppPropertiesPath(): string {
return vscode.workspace.workspaceFolders[0].uri.fsPath + "/.vscode/c_cpp_properties.json";
const wf = vscode.workspace.workspaceFolders?.[0] ?? assert.fail("No workspace folder open");
return `${wf.uri.fsPath}/.vscode/c_cpp_properties.json`;
}
async function changeCppProperties(cppProperties: config.ConfigurationJson, disposables: vscode.Disposable[]): Promise<void> {
async function changeCppProperties(cppProperties: config.ConfigurationJson, _disposables: vscode.Disposable[]): Promise<void> {
await util.writeFileText(cppPropertiesPath(), JSON.stringify(cppProperties));
const contents: string = await util.readFileText(cppPropertiesPath());
console.log(" wrote c_cpp_properties.json: " + contents);
@@ -121,7 +126,7 @@ suite("extensibility tests v3", function(): void {
const provider: api.CustomConfigurationProvider = {
name: "cpptoolsTest-v3",
extensionId: "ms-vscode.cpptools-test3",
canProvideConfiguration(document: vscode.Uri): Thenable<boolean> {
canProvideConfiguration(_document: vscode.Uri): Thenable<boolean> {
return Promise.resolve(true);
},
provideConfigurations(uris: vscode.Uri[]): Thenable<api.SourceFileConfigurationItem[]> {
@@ -145,7 +150,7 @@ suite("extensibility tests v3", function(): void {
canProvideBrowseConfigurationsPerFolder(): Thenable<boolean> {
return Promise.resolve(true);
},
provideFolderBrowseConfiguration(uri: vscode.Uri): Thenable<api.WorkspaceBrowseConfiguration> {
provideFolderBrowseConfiguration(_uri: vscode.Uri): Thenable<api.WorkspaceBrowseConfiguration> {
lastBrowseResult = defaultFolderBrowseConfig;
return Promise.resolve(defaultFolderBrowseConfig);
},
@@ -156,7 +161,7 @@ suite("extensibility tests v3", function(): void {
const disposables: vscode.Disposable[] = [];
suiteSetup(async function(): Promise<void> {
cpptools = await apit.getCppToolsTestApi(api.Version.v3);
cpptools = await apit.getCppToolsTestApi(api.Version.v3) ?? assert.fail('Unable to get the CppToolsTestApi');
cpptools.registerCustomConfigurationProvider(provider);
cpptools.notifyReady(provider);
disposables.push(cpptools);
@@ -174,7 +179,8 @@ suite("extensibility tests v3", function(): void {
test("Check provider - main3.cpp", async () => {
// Open a c++ file to start the language server.
const path: string = vscode.workspace.workspaceFolders[0].uri.fsPath + "/main3.cpp";
const wf = vscode.workspace.workspaceFolders?.[0] ?? assert.fail("No workspace folder open");
const path: string = `${wf.uri.fsPath}/main3.cpp`;
const uri: vscode.Uri = vscode.Uri.file(path);
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
@@ -221,7 +227,7 @@ suite("extensibility tests v2", function(): void {
const provider: any = {
name: "cpptoolsTest-v2",
extensionId: "ms-vscode.cpptools-test2",
canProvideConfiguration(document: vscode.Uri): Thenable<boolean> {
canProvideConfiguration(_document: vscode.Uri): Thenable<boolean> {
return Promise.resolve(true);
},
provideConfigurations(uris: vscode.Uri[]): Thenable<api.SourceFileConfigurationItem[]> {
@@ -249,7 +255,7 @@ suite("extensibility tests v2", function(): void {
const disposables: vscode.Disposable[] = [];
suiteSetup(async function(): Promise<void> {
cpptools = await apit.getCppToolsTestApi(api.Version.v2);
cpptools = await apit.getCppToolsTestApi(api.Version.v2) ?? assert.fail('Unable to get the CppToolsTestApi');
cpptools.registerCustomConfigurationProvider(provider);
cpptools.notifyReady(provider);
disposables.push(cpptools);
@@ -267,7 +273,8 @@ suite("extensibility tests v2", function(): void {
test("Check provider - main2.cpp", async () => {
// Open a c++ file to start the language server.
const path: string = vscode.workspace.workspaceFolders[0].uri.fsPath + "/main2.cpp";
const wf = vscode.workspace.workspaceFolders?.[0] ?? assert.fail("No workspace folder open");
const path: string = `${wf.uri.fsPath}/main2.cpp`;
const uri: vscode.Uri = vscode.Uri.file(path);
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
@@ -308,7 +315,7 @@ suite("extensibility tests v1", function(): void {
const provider: any = {
name: "cpptoolsTest-v1",
extensionId: "ms-vscode.cpptools-test",
canProvideConfiguration(document: vscode.Uri): Thenable<boolean> {
canProvideConfiguration(_document: vscode.Uri): Thenable<boolean> {
return Promise.resolve(true);
},
provideConfigurations(uris: vscode.Uri[]): Thenable<api.SourceFileConfigurationItem[]> {
@@ -329,7 +336,7 @@ suite("extensibility tests v1", function(): void {
const disposables: vscode.Disposable[] = [];
suiteSetup(async function(): Promise<void> {
cpptools = await apit.getCppToolsTestApi(api.Version.v1);
cpptools = await apit.getCppToolsTestApi(api.Version.v1) ?? assert.fail('Unable to get the CppToolsTestApi');
cpptools.registerCustomConfigurationProvider(provider);
disposables.push(cpptools);
@@ -346,7 +353,8 @@ suite("extensibility tests v1", function(): void {
test("Check provider - main1.cpp", async () => {
// Open a c++ file to start the language server.
const path: string = vscode.workspace.workspaceFolders[0].uri.fsPath + "/main1.cpp";
const wf = vscode.workspace.workspaceFolders?.[0] ?? assert.fail("No workspace folder open");
const path: string = `${wf.uri.fsPath}/main1.cpp`;
const uri: vscode.Uri = vscode.Uri.file(path);
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
@@ -384,7 +392,7 @@ suite("extensibility tests v0", function(): void {
// Has to be 'any' instead of api.CustomConfigurationProvider because of missing interface members.
const provider: any = {
name: "cpptoolsTest-v0",
canProvideConfiguration(document: vscode.Uri): Thenable<boolean> {
canProvideConfiguration(_document: vscode.Uri): Thenable<boolean> {
return Promise.resolve(true);
},
provideConfigurations(uris: vscode.Uri[]): Thenable<api.SourceFileConfigurationItem[]> {
@@ -402,7 +410,7 @@ suite("extensibility tests v0", function(): void {
const disposables: vscode.Disposable[] = [];
suiteSetup(async function(): Promise<void> {
cpptools = await apit.getCppToolsTestApi(api.Version.v0);
cpptools = await apit.getCppToolsTestApi(api.Version.v0) ?? assert.fail('Unable to get the CppToolsTestApi');
cpptools.registerCustomConfigurationProvider(provider);
disposables.push(cpptools); // This is a no-op for v0, but do it anyway to make sure nothing breaks.
@@ -420,7 +428,8 @@ suite("extensibility tests v0", function(): void {
test("Check provider - main.cpp", async () => {
// Open a C++ file to start the language server.
const path: string = vscode.workspace.workspaceFolders[0].uri.fsPath + "/main.cpp";
const wf = vscode.workspace.workspaceFolders?.[0] ?? assert.fail("No workspace folder open");
const path: string = `${wf.uri.fsPath}/main.cpp`;
const uri: vscode.Uri = vscode.Uri.file(path);
const testHook: apit.CppToolsTestHook = cpptools.getTestHook();
@@ -1,28 +1,67 @@
import * as path from 'path';
import { runTests } from '@vscode/test-electron';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../../../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './index');
const testWorkspace = path.resolve(extensionDevelopmentPath, 'test/integrationTests/testAssets/SimpleCppProject/simpleCppProject.code-workspace');
const launchArgs = [ "--disable-extensions", testWorkspace ];
// Download VS Code, unzip it and run the integration test
await runTests({ launchArgs, extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron';
import { createHash } from 'crypto';
import { mkdir as md, stat } from 'fs/promises';
import { tmpdir } from 'os';
import { resolve } from 'path';
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = resolve(__dirname, '../../../../');
const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(extensionDevelopmentPath).digest('hex').substring(0,6) );
const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`]
};
async function mkdir(filePath:string) {
filePath = resolve(filePath);
try {
const s = await stat(filePath);
if( s.isDirectory() ) {
return filePath;
}
throw new Error(`Cannot create directory '${filePath}' because thre is a file there.`);
} catch {
// no worries
}
await md(filePath, { recursive: true })
return filePath;
}
async function main() {
try {
// create a folder for the isolated test environment
await mkdir(isolated);
// download VSCode to that location
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...launchArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
// clean up args so that it works with the isolate extensions and data directories
launchArgs.push(`--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`);
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = resolve(__dirname, './index');
const testWorkspace = resolve(extensionDevelopmentPath, 'test/integrationTests/testAssets/SimpleCppProject/simpleCppProject.code-workspace');
launchArgs.push("--disable-extensions", testWorkspace );
// Download VS Code, unzip it and run the integration test
await runTests({
...options,
launchArgs,
extensionDevelopmentPath,
extensionTestsPath
});
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
@@ -2,12 +2,16 @@
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable @typescript-eslint/triple-slash-reference */
/// <reference path="../../vscode.d.ts" />
import { fail } from 'assert';
import * as vscode from 'vscode';
export const defaultTimeout: number = 100000;
export async function activateCppExtension(): Promise<void> {
const extension: vscode.Extension<any> = vscode.extensions.getExtension("ms-vscode.cpptools");
const extension = vscode.extensions.getExtension("ms-vscode.cpptools") ?? fail("Could not get CppTools extension");
if (!extension.isActive) {
await extension.activate();
}
@@ -6,7 +6,7 @@
import { ok, strictEqual, throws } from 'assert';
import { describe } from 'mocha';
import { setTimeout } from 'timers/promises';
import { ManualPromise } from '../../src/Utility/Async/manual-promise';
import { ManualPromise } from '../../src/Utility/Async/manualPromise';
// force dev mode (which throws on duplicate resolve calls)
(global as any).DEVMODE = true;
@@ -6,7 +6,7 @@
import { ok, strictEqual } from 'assert';
import { describe } from 'mocha';
import { setTimeout } from 'timers/promises';
import { ManualSignal } from '../../src/Utility/Async/manual-signal';
import { ManualSignal } from '../../src/Utility/Async/manualSignal';
import { Signal } from '../../src/Utility/Async/signal';
describe('Signal', () => {
+65 -26
View File
@@ -1,26 +1,65 @@
import * as path from 'path';
import { runTests } from '@vscode/test-electron';
async function main() {
try {
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = path.resolve(__dirname, '../../../');
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = path.resolve(__dirname, './index');
const launchArgs = [ "--disable-extensions" ];
// Download VS Code, unzip it and run the integration test
await runTests({ launchArgs, extensionDevelopmentPath, extensionTestsPath });
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
import { downloadAndUnzipVSCode, resolveCliArgsFromVSCodeExecutablePath, runTests } from '@vscode/test-electron';
import { createHash } from 'crypto';
import { mkdir as md, stat } from 'fs/promises';
import { tmpdir } from 'os';
import { resolve } from 'path';
// The folder containing the Extension Manifest package.json
// Passed to `--extensionDevelopmentPath`
const extensionDevelopmentPath = resolve(__dirname, '../../../');
const isolated = resolve(tmpdir(), '.vscode-test', createHash('sha256').update(extensionDevelopmentPath).digest('hex').substring(0,6) );
const options = {
cachePath: `${isolated}/cache`,
launchArgs: ['--no-sandbox', '--disable-updates', '--skip-welcome', '--skip-release-notes', `--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`]
};
async function mkdir(filePath:string) {
filePath = resolve(filePath);
try {
const s = await stat(filePath);
if( s.isDirectory() ) {
return filePath;
}
throw new Error(`Cannot create directory '${filePath}' because thre is a file there.`);
} catch {
// no worries
}
await md(filePath, { recursive: true })
return filePath;
}
async function main() {
try {
// create a folder for the isolated test environment
await mkdir(isolated);
// download VSCode to that location
const vscodeExecutablePath = await downloadAndUnzipVSCode(options);
const [cli, ...launchArgs] = resolveCliArgsFromVSCodeExecutablePath(vscodeExecutablePath).filter(each => !each.startsWith('--extensions-dir=') && !each.startsWith('--user-data-dir='));
// clean up args so that it works with the isolate extensions and data directories
launchArgs.push(`--extensions-dir=${isolated}/extensions`, `--user-data-dir=${isolated}/user-data`);
// The path to the extension test script
// Passed to --extensionTestsPath
const extensionTestsPath = resolve(__dirname, './index');
launchArgs.push("--disable-extensions");
// Download VS Code, unzip it and run the integration test
await runTests({
...options,
launchArgs,
extensionDevelopmentPath,
extensionTestsPath
});
} catch (err) {
console.log(err);
console.log('Failed to run tests.');
process.exit(1);
}
}
main();
+5 -3
View File
@@ -1,8 +1,10 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* Copyright (c) Microsoft Corporation. All Rights Reserved.
* See 'LICENSE' in the project root for license information.
* ------------------------------------------------------------------------------------------ */
/* eslint-disable no-prototype-builtins */
import * as fs from 'fs';
import * as os from 'os';
@@ -132,7 +134,7 @@ function generateOptionsSchema(): void {
packageJSON.contributes.debuggers[1].configurationAttributes.launch = schemaJSON.definitions.CppvsdbgLaunchOptions;
packageJSON.contributes.debuggers[1].configurationAttributes.attach = schemaJSON.definitions.CppvsdbgAttachOptions;
let content: string = JSON.stringify(packageJSON, null, 2);
let content: string = JSON.stringify(packageJSON, null, 4);
if (os.platform() === 'win32') {
content = content.replace(/\n/gm, "\r\n");
}
+39 -97
View File
@@ -530,15 +530,15 @@
"@microsoft/1ds-core-js" "^3.2.3"
"@microsoft/1ds-post-js" "^3.2.3"
"@vscode/test-electron@^1.6.1":
version "1.6.2"
resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-1.6.2.tgz#f639cab19a0013949015079dcfd2ff0c1aa88a1b"
integrity sha512-W01ajJEMx6223Y7J5yaajGjVs1QfW3YGkkOJHVKfAMEqNB1ZHN9wCcViehv5ZwVSSJnjhu6lYEYgwBdHtCxqhQ==
"@vscode/test-electron@^2.3.3":
version "2.3.3"
resolved "https://registry.yarnpkg.com/@vscode/test-electron/-/test-electron-2.3.3.tgz#e648700d5848eccfda99efa5d839356cfbe8cd4e"
integrity sha512-hgXCkDP0ibboF1K6seqQYyHAzCURgTwHS/6QU7slhwznDLwsRwg9bhfw1CZdyUEw8vvCmlrKWnd7BlQnI0BC4w==
dependencies:
http-proxy-agent "^4.0.1"
https-proxy-agent "^5.0.0"
rimraf "^3.0.2"
unzipper "^0.10.11"
jszip "^3.10.1"
semver "^7.3.8"
"@webassemblyjs/[email protected]", "@webassemblyjs/ast@^1.11.5":
version "1.11.6"
@@ -1063,11 +1063,6 @@ before-after-hook@^2.2.0:
resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.3.tgz#c51e809c81a4e354084422b9b26bad88249c517c"
integrity sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ==
big-integer@^1.6.17:
version "1.6.51"
resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.51.tgz#0df92a5d9880560d3ff2d5fd20245c889d130686"
integrity sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==
big.js@^5.2.2:
version "5.2.2"
resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
@@ -1078,14 +1073,6 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
binary@~0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/binary/-/binary-0.3.0.tgz#9f60553bc5ce8c3386f3b553cff47462adecaa79"
integrity sha512-D4H1y5KYwpJgK8wk1Cue5LLPgmwHKYSChkbspQg5JtVuR5ulGckxfR62H3AE9UDkdMC8yyXlqYihuz3Aqg2XZg==
dependencies:
buffers "~0.1.1"
chainsaw "~0.1.0"
bl@^5.0.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-5.1.0.tgz#183715f678c7188ecef9fe475d90209400624273"
@@ -1095,11 +1082,6 @@ bl@^5.0.0:
inherits "^2.0.4"
readable-stream "^3.4.0"
bluebird@~3.4.1:
version "3.4.7"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3"
integrity sha512-iD3898SR7sWVRHbiQv+sHUtHnMvC1o3nW5rAcqnq3uOn07DSAppZYUkIGslDz6gXC7HfunPe7YVBgoEJASPcHA==
brace-expansion@^1.1.7:
version "1.1.11"
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
@@ -1168,11 +1150,6 @@ buffer-from@^1.0.0:
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
buffer-indexof-polyfill@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz#d2732135c5999c64b277fcf9b1abe3498254729c"
integrity sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==
buffer@^6.0.3:
version "6.0.3"
resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6"
@@ -1181,11 +1158,6 @@ buffer@^6.0.3:
base64-js "^1.3.1"
ieee754 "^1.2.1"
buffers@~0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/buffers/-/buffers-0.1.1.tgz#b24579c3bed4d6d396aeee6d9a8ae7f5482ab7bb"
integrity sha512-9q/rDEGSb/Qsvv2qvzIzdluL5k7AaJOTrw23z9reQthrbF7is4CtlT0DXyO1oei2DCp4uojjzQ7igaSHp1kAEQ==
builtin-modules@^3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.3.0.tgz#cae62812b89801e9656336e46223e030386be7b6"
@@ -1234,13 +1206,6 @@ caniuse-lite@^1.0.30001503:
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001515.tgz#418aefeed9d024cd3129bfae0ccc782d4cb8f12b"
integrity sha512-eEFDwUOZbE24sb+Ecsx3+OvNETqjWIdabMy52oOkIgcUtAsQifjUG9q4U9dgTHJM2mfk4uEPxc0+xuFdJ629QA==
chainsaw@~0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/chainsaw/-/chainsaw-0.1.0.tgz#5eab50b28afe58074d0d58291388828b5e5fbc98"
integrity sha512-75kWfWt6MEKNC8xYXIdRpDehRYY/tNSgwKaJq+dbbDcxORuVrrQ+SEHoWsniVn9XPYfP4gmdWIeDk/4YNp1rNQ==
dependencies:
traverse ">=0.3.0 <0.4"
chalk@^4.0.0, chalk@^4.1.0:
version "4.1.2"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
@@ -1634,13 +1599,6 @@ doctrine@^3.0.0:
dependencies:
esutils "^2.0.2"
duplexer2@~0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1"
integrity sha512-asLFVfWWtJ90ZyOUHMqk7/S2w2guQKxUI2itj3d92ADHhxUSbCMGi1f1cBcJ7xM1To+pE/Khbwo1yuNbMEPKeA==
dependencies:
readable-stream "^2.0.2"
duplexer@^0.1.1, duplexer@~0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6"
@@ -2402,16 +2360,6 @@ fsevents@~2.3.2:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
fstream@^1.0.12:
version "1.0.12"
resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
dependencies:
graceful-fs "^4.1.2"
inherits "~2.0.0"
mkdirp ">=0.5 0"
rimraf "2"
function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -2633,7 +2581,7 @@ gopd@^1.0.1:
dependencies:
get-intrinsic "^1.1.3"
[email protected], graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.2, graceful-fs@^4.2.4, graceful-fs@^4.2.8, graceful-fs@^4.2.9:
[email protected], graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.10, graceful-fs@^4.2.11, graceful-fs@^4.2.4, graceful-fs@^4.2.8, graceful-fs@^4.2.9:
version "4.2.11"
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3"
integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==
@@ -2902,6 +2850,11 @@ ignore@^5.2.0:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.4.tgz#a291c0c6178ff1b960befe47fcdec301674a6324"
integrity sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==
immediate@~3.0.5:
version "3.0.6"
resolved "https://registry.yarnpkg.com/immediate/-/immediate-3.0.6.tgz#9db1dbd0faf8de6fbe0f5dd5e56bb606280de69b"
integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==
import-fresh@^3.0.0, import-fresh@^3.2.1:
version "3.3.0"
resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
@@ -2931,7 +2884,7 @@ inflight@^1.0.4:
once "^1.3.0"
wrappy "1"
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3:
inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3:
version "2.0.4"
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
@@ -3370,6 +3323,16 @@ jsonfile@^4.0.0:
optionalDependencies:
graceful-fs "^4.1.6"
jszip@^3.10.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/jszip/-/jszip-3.10.1.tgz#34aee70eb18ea1faec2f589208a157d1feb091c2"
integrity sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==
dependencies:
lie "~3.3.0"
pako "~1.0.2"
readable-stream "~2.3.6"
setimmediate "^1.0.5"
just-debounce@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/just-debounce/-/just-debounce-1.1.0.tgz#2f81a3ad4121a76bc7cb45dbf704c0d76a8e5ddf"
@@ -3446,6 +3409,13 @@ levn@^0.4.1:
prelude-ls "^1.2.1"
type-check "~0.4.0"
lie@~3.3.0:
version "3.3.0"
resolved "https://registry.yarnpkg.com/lie/-/lie-3.3.0.tgz#dcf82dee545f46074daf200c7c1c5a08e0f40f6a"
integrity sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==
dependencies:
immediate "~3.0.5"
liftoff@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-3.1.0.tgz#c9ba6081f908670607ee79062d700df062c52ed3"
@@ -3460,11 +3430,6 @@ liftoff@^3.1.0:
rechoir "^0.6.2"
resolve "^1.1.7"
listenercount@~1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/listenercount/-/listenercount-1.0.1.tgz#84c8a72ab59c4725321480c975e6508342e70937"
integrity sha512-3mk/Zag0+IJxeDrxSgaDPy4zZ3w05PRZeJNnlWhzFz5OkX49J4krc+A8X2d2M69vGMBEX0uyl8M+W+8gH+kBqQ==
load-json-file@^1.0.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0"
@@ -3690,7 +3655,7 @@ mixin-deep@^1.2.0:
for-in "^1.0.2"
is-extendable "^1.0.1"
"mkdirp@>=0.5 0", mkdirp@^0.5.5:
mkdirp@^0.5.5:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
@@ -4056,6 +4021,11 @@ p-try@^2.0.0:
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
pako@~1.0.2:
version "1.0.11"
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
parent-module@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
@@ -4345,7 +4315,7 @@ read-pkg@^1.0.0:
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.5, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.8"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.8.tgz#91125e8042bba1b9887f49345f6277027ce8be9b"
integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==
@@ -4525,13 +4495,6 @@ reusify@^1.0.4:
resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
rimraf@2:
version "2.7.1"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec"
integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==
dependencies:
glob "^7.1.3"
rimraf@^3.0.0, rimraf@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
@@ -4608,7 +4571,7 @@ semver@^6.3.0:
resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4"
integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==
semver@^7.3.4, semver@^7.3.7, semver@^7.5.1, semver@^7.5.3:
semver@^7.3.4, semver@^7.3.7, semver@^7.3.8, semver@^7.5.1, semver@^7.5.3:
version "7.5.4"
resolved "https://registry.yarnpkg.com/semver/-/semver-7.5.4.tgz#483986ec4ed38e1c6c48c34894a9182dbff68a6e"
integrity sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==
@@ -4651,7 +4614,7 @@ set-value@^2.0.0, set-value@^2.0.1:
is-plain-object "^2.0.3"
split-string "^3.0.1"
setimmediate@~1.0.4:
setimmediate@^1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==
@@ -5198,11 +5161,6 @@ tr46@~0.0.3:
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
"traverse@>=0.3.0 <0.4":
version "0.3.9"
resolved "https://registry.yarnpkg.com/traverse/-/traverse-0.3.9.tgz#717b8f220cc0bb7b44e40514c22b2e8bbc70d8b9"
integrity sha512-iawgk0hLP3SxGKDfnDJf8wTz4p2qImnyihM5Hh/sGvQ3K37dPi/w8sRhdNIxYA1TwFwc5mDhIJq+O0RsvXBKdQ==
ts-loader@^8.1.0:
version "8.4.0"
resolved "https://registry.yarnpkg.com/ts-loader/-/ts-loader-8.4.0.tgz#e845ea0f38d140bdc3d7d60293ca18d12ff2720f"
@@ -5354,22 +5312,6 @@ unset-value@^1.0.0:
has-value "^0.3.1"
isobject "^3.0.0"
unzipper@^0.10.11:
version "0.10.14"
resolved "https://registry.yarnpkg.com/unzipper/-/unzipper-0.10.14.tgz#d2b33c977714da0fbc0f82774ad35470a7c962b1"
integrity sha512-ti4wZj+0bQTiX2KmKWuwj7lhV+2n//uXEotUmGuQqrbVZSEGFMbI68+c6JCQ8aAmUWYvtHEz2A8K6wXvueR/6g==
dependencies:
big-integer "^1.6.17"
binary "~0.3.0"
bluebird "~3.4.1"
buffer-indexof-polyfill "~1.0.0"
duplexer2 "~0.1.4"
fstream "^1.0.12"
graceful-fs "^4.2.2"
listenercount "~1.0.1"
readable-stream "~2.3.6"
setimmediate "~1.0.4"
update-browserslist-db@^1.0.11:
version "1.0.11"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.11.tgz#9a2a641ad2907ae7b3616506f4b977851db5b940"