Merge branch 'main' into suggest-notify

This commit is contained in:
Jacob Jaeggli
2023-07-28 10:28:27 -07:00
committed by GitHub
123 changed files with 11703 additions and 1282 deletions
+33
View File
@@ -0,0 +1,33 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { TSESTree } from '@typescript-eslint/experimental-utils';
import * as eslint from 'eslint';
function isCallExpression(node: TSESTree.Node): node is TSESTree.CallExpression {
return node.type === 'CallExpression';
}
function isFunctionExpression(node: TSESTree.Node): node is TSESTree.FunctionExpression {
return node.type.includes('FunctionExpression');
}
export = new class NoAsyncSuite implements eslint.Rule.RuleModule {
create(context: eslint.Rule.RuleContext): eslint.Rule.RuleListener {
function hasAsyncSuite(node: any) {
if (isCallExpression(node) && node.arguments.length >= 2 && isFunctionExpression(node.arguments[1]) && node.arguments[1].async) {
return context.report({
node: node as any,
message: 'suite factory function should never be async'
});
}
}
return {
['CallExpression[callee.name=/suite$/][arguments]']: hasAsyncSuite,
};
}
};
+1
View File
@@ -120,6 +120,7 @@
],
"rules": {
"local/code-no-test-only": "error",
"local/code-no-test-async-suite": "warn",
"local/code-no-unexternalized-strings": "off"
}
},
-1
View File
@@ -281,7 +281,6 @@
"workbench-editor-resolver": {"assign": ["lramos15"]},
"workbench-editors": {"assign": ["bpasero"]},
"workbench-electron": {"assign": ["deepak1556"]},
"workbench-feedback": {"assign": ["bpasero"]},
"workbench-fonts": {"assign": []},
"workbench-history": {"assign": ["bpasero"]},
"workbench-hot-exit": {"assign": ["bpasero"]},
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+3 -4
View File
@@ -231,15 +231,14 @@ async function main(): Promise<void> {
if (rejectedPromiseResults.length === 0) {
console.log('All blobs successfully uploaded.');
} else if (rejectedPromiseResults[0].reason?.message?.includes('already exists')) {
} else if (rejectedPromiseResults[0]?.reason?.message?.includes('already exists')) {
console.warn(rejectedPromiseResults[0].reason.message);
console.log('Some blobs successfully uploaded.');
} else {
throw rejectedPromiseResults[0].reason;
// eslint-disable-next-line no-throw-literal
throw rejectedPromiseResults[0]?.reason;
}
console.log('All blobs successfully uploaded.');
const assetUrl = `${process.env['AZURE_CDN_URL']}/${quality}/${blobName}`;
const blobPath = new URL(assetUrl).pathname;
const mooncakeUrl = `${process.env['MOONCAKE_CDN_URL']}${blobPath}`;
+3 -2
View File
@@ -46,11 +46,12 @@ async function main(force) {
await (0, retry_1.retry)(() => scripts.storedProcedure('releaseBuild').execute('', [commit]));
}
const [, , force] = process.argv;
main(force === 'true').then(() => {
console.log(process.argv);
main(/^true$/i.test(force)).then(() => {
console.log('Build successfully released');
process.exit(0);
}, err => {
console.error(err);
process.exit(1);
});
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsZWFzZUJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVsZWFzZUJ1aWxkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7QUFFaEcsOENBQXlEO0FBQ3pELDBDQUE2QztBQUM3QyxtQ0FBZ0M7QUFFaEMsU0FBUyxNQUFNLENBQUMsSUFBWTtJQUMzQixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWpDLElBQUksT0FBTyxNQUFNLEtBQUssV0FBVyxFQUFFO1FBQ2xDLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxDQUFDO0tBQ3hDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDZixDQUFDO0FBT0QsU0FBUyxtQkFBbUIsQ0FBQyxPQUFlO0lBQzNDLE9BQU87UUFDTixFQUFFLEVBQUUsT0FBTztRQUNYLE1BQU0sRUFBRSxLQUFLO0tBQ2IsQ0FBQztBQUNILENBQUM7QUFFRCxLQUFLLFVBQVUsU0FBUyxDQUFDLE1BQW9CLEVBQUUsT0FBZTtJQUM3RCxNQUFNLEtBQUssR0FBRyx1Q0FBdUMsT0FBTyxHQUFHLENBQUM7SUFFaEUsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBRTlGLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQy9CLE9BQU8sbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDcEM7SUFFRCxPQUFPLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFXLENBQUM7QUFDbkMsQ0FBQztBQUVELEtBQUssVUFBVSxJQUFJLENBQUMsS0FBYztJQUNqQyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUM3QyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUV6QyxNQUFNLGNBQWMsR0FBRyxJQUFJLGlDQUFzQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFFLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBRSxDQUFDLENBQUM7SUFDekosTUFBTSxNQUFNLEdBQUcsSUFBSSxxQkFBWSxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO0lBRXpHLElBQUksQ0FBQyxLQUFLLEVBQUU7UUFDWCxNQUFNLE1BQU0sR0FBRyxNQUFNLFNBQVMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUV2QyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUU7WUFDbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQ0FBb0MsT0FBTyxhQUFhLENBQUMsQ0FBQztZQUN0RSxPQUFPO1NBQ1A7S0FDRDtJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLE1BQU0sS0FBSyxDQUFDLENBQUM7SUFFNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDO0lBQ3JFLE1BQU0sSUFBQSxhQUFLLEVBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2xGLENBQUM7QUFFRCxNQUFNLENBQUMsRUFBRSxBQUFELEVBQUcsS0FBSyxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztBQUVqQyxJQUFJLENBQUMsS0FBSyxLQUFLLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7SUFDaEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakIsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFO0lBQ1IsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pCLENBQUMsQ0FBQyxDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVsZWFzZUJ1aWxkLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVsZWFzZUJ1aWxkLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7QUFFaEcsOENBQXlEO0FBQ3pELDBDQUE2QztBQUM3QyxtQ0FBZ0M7QUFFaEMsU0FBUyxNQUFNLENBQUMsSUFBWTtJQUMzQixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWpDLElBQUksT0FBTyxNQUFNLEtBQUssV0FBVyxFQUFFO1FBQ2xDLE1BQU0sSUFBSSxLQUFLLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxDQUFDO0tBQ3hDO0lBRUQsT0FBTyxNQUFNLENBQUM7QUFDZixDQUFDO0FBT0QsU0FBUyxtQkFBbUIsQ0FBQyxPQUFlO0lBQzNDLE9BQU87UUFDTixFQUFFLEVBQUUsT0FBTztRQUNYLE1BQU0sRUFBRSxLQUFLO0tBQ2IsQ0FBQztBQUNILENBQUM7QUFFRCxLQUFLLFVBQVUsU0FBUyxDQUFDLE1BQW9CLEVBQUUsT0FBZTtJQUM3RCxNQUFNLEtBQUssR0FBRyx1Q0FBdUMsT0FBTyxHQUFHLENBQUM7SUFFaEUsTUFBTSxHQUFHLEdBQUcsTUFBTSxNQUFNLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBRTlGLElBQUksR0FBRyxDQUFDLFNBQVMsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQy9CLE9BQU8sbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7S0FDcEM7SUFFRCxPQUFPLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFXLENBQUM7QUFDbkMsQ0FBQztBQUVELEtBQUssVUFBVSxJQUFJLENBQUMsS0FBYztJQUNqQyxNQUFNLE1BQU0sR0FBRyxNQUFNLENBQUMscUJBQXFCLENBQUMsQ0FBQztJQUM3QyxNQUFNLE9BQU8sR0FBRyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztJQUV6QyxNQUFNLGNBQWMsR0FBRyxJQUFJLGlDQUFzQixDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsaUJBQWlCLENBQUUsRUFBRSxPQUFPLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFFLEVBQUUsT0FBTyxDQUFDLEdBQUcsQ0FBQyxxQkFBcUIsQ0FBRSxDQUFDLENBQUM7SUFDekosTUFBTSxNQUFNLEdBQUcsSUFBSSxxQkFBWSxDQUFDLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLENBQUUsRUFBRSxjQUFjLEVBQUUsQ0FBQyxDQUFDO0lBRXpHLElBQUksQ0FBQyxLQUFLLEVBQUU7UUFDWCxNQUFNLE1BQU0sR0FBRyxNQUFNLFNBQVMsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFaEQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUV2QyxJQUFJLE1BQU0sQ0FBQyxNQUFNLEVBQUU7WUFDbEIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxvQ0FBb0MsT0FBTyxhQUFhLENBQUMsQ0FBQztZQUN0RSxPQUFPO1NBQ1A7S0FDRDtJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsbUJBQW1CLE1BQU0sS0FBSyxDQUFDLENBQUM7SUFFNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxDQUFDO0lBQ3JFLE1BQU0sSUFBQSxhQUFLLEVBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsQ0FBQyxjQUFjLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2xGLENBQUM7QUFFRCxNQUFNLENBQUMsRUFBRSxBQUFELEVBQUcsS0FBSyxDQUFDLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQztBQUVqQyxPQUFPLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztBQUUxQixJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUU7SUFDckMsT0FBTyxDQUFDLEdBQUcsQ0FBQyw2QkFBNkIsQ0FBQyxDQUFDO0lBQzNDLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDakIsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxFQUFFO0lBQ1IsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNuQixPQUFPLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2pCLENBQUMsQ0FBQyxDQUFDIn0=
+3 -1
View File
@@ -67,7 +67,9 @@ async function main(force: boolean): Promise<void> {
const [, , force] = process.argv;
main(force === 'true').then(() => {
console.log(process.argv);
main(/^true$/i.test(force)).then(() => {
console.log('Build successfully released');
process.exit(0);
}, err => {
-4
View File
@@ -86,10 +86,6 @@
"name": "vs/workbench/contrib/externalTerminal",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/feedback",
"project": "vscode-workbench"
},
{
"name": "vs/workbench/contrib/files",
"project": "vscode-workbench"
+10 -2
View File
@@ -71,10 +71,18 @@ function calculatePackageDeps(binaryPath, arch, sysroot) {
// on the newer package, this hack skips the dep. This is safe because
// libgcc-s1 is a dependency of libc6. This hack can be removed once
// support for Debian Buster and Ubuntu Bionic are dropped.
//
// Remove kerberos native module related dependencies as the versions
// computed from sysroot will not satisfy the minimum supported distros
// Refs https://github.com/microsoft/vscode/issues/188881.
// TODO(deepak1556): remove this workaround in favor of computing the
// versions from build container for native modules.
const filteredDeps = depsStr.split(', ').filter(dependency => {
return !dependency.startsWith('libgcc-s1');
return !dependency.startsWith('libgcc-s1') &&
!dependency.startsWith('libgssapi-krb5-2') &&
!dependency.startsWith('libkrb5-3');
}).sort();
const requires = new Set(filteredDeps);
return requires;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsY3VsYXRlLWRlcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjYWxjdWxhdGUtZGVwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyxpREFBMEM7QUFDMUMsMkJBQXlDO0FBQ3pDLDJCQUE0QjtBQUM1Qiw2QkFBOEI7QUFDOUIsc0RBQXNEO0FBQ3RELDJDQUE2QztBQUc3QyxTQUFnQixtQkFBbUIsQ0FBQyxLQUFlLEVBQUUsSUFBc0IsRUFBRSxPQUFlO0lBQzNGLE1BQU0sWUFBWSxHQUFrQixLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsb0JBQW9CLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2pHLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLENBQUMsMEJBQWMsQ0FBQyxDQUFDO0lBQ2xELFlBQVksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUNyQyxPQUFPLFlBQVksQ0FBQztBQUNyQixDQUFDO0FBTEQsa0RBS0M7QUFFRCw2SEFBNkg7QUFDN0gsU0FBUyxvQkFBb0IsQ0FBQyxVQUFrQixFQUFFLElBQXNCLEVBQUUsT0FBZTtJQUN4RixJQUFJO1FBQ0gsSUFBSSxDQUFDLENBQUMsSUFBQSxhQUFRLEVBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxHQUFHLGNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUNyRCxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsVUFBVSx1Q0FBdUMsQ0FBQyxDQUFDO1NBQzdFO0tBQ0Q7SUFBQyxPQUFPLENBQUMsRUFBRTtRQUNYLDhEQUE4RDtRQUM5RCxPQUFPLENBQUMsS0FBSyxDQUFDLGdCQUFnQixHQUFHLFVBQVUsR0FBRyxjQUFjLENBQUMsQ0FBQztLQUM5RDtJQUVELHdDQUF3QztJQUN4QyxNQUFNLGdCQUFnQixHQUFHLFNBQVMsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFO1FBQ3RFLE9BQU8sWUFBWSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEtBQUssS0FBSyxJQUFJLFlBQVksQ0FBQyxTQUFTLENBQUMsR0FBSSxDQUFDLElBQUksS0FBSyxVQUFVLENBQUM7SUFDakcsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLGdCQUFnQixHQUFHLHVEQUF1RCxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLCtDQUErQyxDQUFDO0lBQzNKLE1BQU0sMkJBQTJCLEdBQUcsR0FBRyxJQUFBLFdBQU0sR0FBRSxvQkFBb0IsQ0FBQztJQUNwRSxNQUFNLE1BQU0sR0FBRyxJQUFBLHlCQUFTLEVBQUMsTUFBTSxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLDJCQUEyQixDQUFDLENBQUMsQ0FBQztJQUN4RixJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQzdFO0lBQ0QsTUFBTSxHQUFHLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDO0lBQ3JFLFFBQVEsSUFBSSxFQUFFO1FBQ2IsS0FBSyxPQUFPO1lBQ1gsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLE9BQU8sMkJBQTJCLEVBQy9DLEtBQUssT0FBTyx1QkFBdUIsQ0FBQyxDQUFDO1lBQ3RDLE1BQU07UUFDUCxLQUFLLE9BQU87WUFDWCxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssT0FBTyw4QkFBOEIsRUFDbEQsS0FBSyxPQUFPLDBCQUEwQixDQUFDLENBQUM7WUFDekMsTUFBTTtRQUNQLEtBQUssT0FBTztZQUNYLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxPQUFPLDRCQUE0QixFQUNoRCxLQUFLLE9BQU8sd0JBQXdCLENBQUMsQ0FBQztZQUN2QyxNQUFNO0tBQ1A7SUFDRCxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssT0FBTyxVQUFVLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRS9DLE1BQU0sbUJBQW1CLEdBQUcsSUFBQSx5QkFBUyxFQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRSxJQUFJLG1CQUFtQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFDckMsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsbUJBQW1CLENBQUMsTUFBTSxjQUFjLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7S0FDL0g7SUFFRCxNQUFNLG1CQUFtQixHQUFHLGlCQUFpQixDQUFDO0lBQzlDLE1BQU0sWUFBWSxHQUFHLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hGLElBQUksT0FBTyxHQUFHLEVBQUUsQ0FBQztJQUNqQixLQUFLLE1BQU0sSUFBSSxJQUFJLFlBQVksRUFBRTtRQUNoQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsbUJBQW1CLENBQUMsRUFBRTtZQUN6QyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNyRDtLQUNEO0lBQ0QseUVBQXlFO0lBQ3pFLDBFQUEwRTtJQUMxRSx5RUFBeUU7SUFDekUsdUVBQXVFO0lBQ3ZFLHFFQUFxRTtJQUNyRSwyREFBMkQ7SUFDM0QsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUU7UUFDNUQsT0FBTyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDNUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDVixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUN2QyxPQUFPLFFBQVEsQ0FBQztBQUNqQixDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsY3VsYXRlLWRlcHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJjYWxjdWxhdGUtZGVwcy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiO0FBQUE7OztnR0FHZ0c7OztBQUVoRyxpREFBMEM7QUFDMUMsMkJBQXlDO0FBQ3pDLDJCQUE0QjtBQUM1Qiw2QkFBOEI7QUFDOUIsc0RBQXNEO0FBQ3RELDJDQUE2QztBQUc3QyxTQUFnQixtQkFBbUIsQ0FBQyxLQUFlLEVBQUUsSUFBc0IsRUFBRSxPQUFlO0lBQzNGLE1BQU0sWUFBWSxHQUFrQixLQUFLLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsb0JBQW9CLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ2pHLE1BQU0saUJBQWlCLEdBQUcsSUFBSSxHQUFHLENBQUMsMEJBQWMsQ0FBQyxDQUFDO0lBQ2xELFlBQVksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUNyQyxPQUFPLFlBQVksQ0FBQztBQUNyQixDQUFDO0FBTEQsa0RBS0M7QUFFRCw2SEFBNkg7QUFDN0gsU0FBUyxvQkFBb0IsQ0FBQyxVQUFrQixFQUFFLElBQXNCLEVBQUUsT0FBZTtJQUN4RixJQUFJO1FBQ0gsSUFBSSxDQUFDLENBQUMsSUFBQSxhQUFRLEVBQUMsVUFBVSxDQUFDLENBQUMsSUFBSSxHQUFHLGNBQVMsQ0FBQyxPQUFPLENBQUMsRUFBRTtZQUNyRCxNQUFNLElBQUksS0FBSyxDQUFDLFVBQVUsVUFBVSx1Q0FBdUMsQ0FBQyxDQUFDO1NBQzdFO0tBQ0Q7SUFBQyxPQUFPLENBQUMsRUFBRTtRQUNYLDhEQUE4RDtRQUM5RCxPQUFPLENBQUMsS0FBSyxDQUFDLGdCQUFnQixHQUFHLFVBQVUsR0FBRyxjQUFjLENBQUMsQ0FBQztLQUM5RDtJQUVELHdDQUF3QztJQUN4QyxNQUFNLGdCQUFnQixHQUFHLFNBQVMsQ0FBQyxhQUFhLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxFQUFFO1FBQ3RFLE9BQU8sWUFBWSxDQUFDLFNBQVMsQ0FBQyxJQUFJLEtBQUssS0FBSyxJQUFJLFlBQVksQ0FBQyxTQUFTLENBQUMsR0FBSSxDQUFDLElBQUksS0FBSyxVQUFVLENBQUM7SUFDakcsQ0FBQyxDQUFDLENBQUM7SUFDSCxNQUFNLGdCQUFnQixHQUFHLHVEQUF1RCxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLCtDQUErQyxDQUFDO0lBQzNKLE1BQU0sMkJBQTJCLEdBQUcsR0FBRyxJQUFBLFdBQU0sR0FBRSxvQkFBb0IsQ0FBQztJQUNwRSxNQUFNLE1BQU0sR0FBRyxJQUFBLHlCQUFTLEVBQUMsTUFBTSxFQUFFLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxFQUFFLDJCQUEyQixDQUFDLENBQUMsQ0FBQztJQUN4RixJQUFJLE1BQU0sQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1FBQ3hCLE1BQU0sSUFBSSxLQUFLLENBQUMsMkNBQTJDLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0tBQzdFO0lBQ0QsTUFBTSxHQUFHLEdBQUcsQ0FBQywyQkFBMkIsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDO0lBQ3JFLFFBQVEsSUFBSSxFQUFFO1FBQ2IsS0FBSyxPQUFPO1lBQ1gsR0FBRyxDQUFDLElBQUksQ0FBQyxLQUFLLE9BQU8sMkJBQTJCLEVBQy9DLEtBQUssT0FBTyx1QkFBdUIsQ0FBQyxDQUFDO1lBQ3RDLE1BQU07UUFDUCxLQUFLLE9BQU87WUFDWCxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssT0FBTyw4QkFBOEIsRUFDbEQsS0FBSyxPQUFPLDBCQUEwQixDQUFDLENBQUM7WUFDekMsTUFBTTtRQUNQLEtBQUssT0FBTztZQUNYLEdBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxPQUFPLDRCQUE0QixFQUNoRCxLQUFLLE9BQU8sd0JBQXdCLENBQUMsQ0FBQztZQUN2QyxNQUFNO0tBQ1A7SUFDRCxHQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssT0FBTyxVQUFVLENBQUMsQ0FBQztJQUNqQyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBRS9DLE1BQU0sbUJBQW1CLEdBQUcsSUFBQSx5QkFBUyxFQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsRUFBRSxHQUFHLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztJQUNyRSxJQUFJLG1CQUFtQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUU7UUFDckMsTUFBTSxJQUFJLEtBQUssQ0FBQyx3Q0FBd0MsbUJBQW1CLENBQUMsTUFBTSxjQUFjLG1CQUFtQixDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7S0FDL0g7SUFFRCxNQUFNLG1CQUFtQixHQUFHLGlCQUFpQixDQUFDO0lBQzlDLE1BQU0sWUFBWSxHQUFHLG1CQUFtQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hGLElBQUksT0FBTyxHQUFHLEVBQUUsQ0FBQztJQUNqQixLQUFLLE1BQU0sSUFBSSxJQUFJLFlBQVksRUFBRTtRQUNoQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsbUJBQW1CLENBQUMsRUFBRTtZQUN6QyxPQUFPLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxtQkFBbUIsQ0FBQyxNQUFNLENBQUMsQ0FBQztTQUNyRDtLQUNEO0lBQ0QseUVBQXlFO0lBQ3pFLDBFQUEwRTtJQUMxRSx5RUFBeUU7SUFDekUsdUVBQXVFO0lBQ3ZFLHFFQUFxRTtJQUNyRSwyREFBMkQ7SUFDM0QsRUFBRTtJQUNGLHFFQUFxRTtJQUNyRSx1RUFBdUU7SUFDdkUsMERBQTBEO0lBQzFELHFFQUFxRTtJQUNyRSxvREFBb0Q7SUFDcEQsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLEVBQUU7UUFDNUQsT0FBTyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDO1lBQ3pDLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxrQkFBa0IsQ0FBQztZQUMxQyxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdEMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDVixNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUN2QyxPQUFPLFFBQVEsQ0FBQztBQUNqQixDQUFDIn0=
+9 -1
View File
@@ -76,8 +76,16 @@ function calculatePackageDeps(binaryPath: string, arch: DebianArchString, sysroo
// on the newer package, this hack skips the dep. This is safe because
// libgcc-s1 is a dependency of libc6. This hack can be removed once
// support for Debian Buster and Ubuntu Bionic are dropped.
//
// Remove kerberos native module related dependencies as the versions
// computed from sysroot will not satisfy the minimum supported distros
// Refs https://github.com/microsoft/vscode/issues/188881.
// TODO(deepak1556): remove this workaround in favor of computing the
// versions from build container for native modules.
const filteredDeps = depsStr.split(', ').filter(dependency => {
return !dependency.startsWith('libgcc-s1');
return !dependency.startsWith('libgcc-s1') &&
!dependency.startsWith('libgssapi-krb5-2') &&
!dependency.startsWith('libkrb5-3');
}).sort();
const requires = new Set(filteredDeps);
return requires;
+10 -8
View File
@@ -12,7 +12,9 @@ exports.additionalDeps = [
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libnss3 (>= 3.26)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'xdg-utils (>= 1.0.2)' // OS integration
'xdg-utils (>= 1.0.2)',
'libgssapi-krb5-2',
'libkrb5-3',
];
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends
// Dependencies that we can only recommend
@@ -38,10 +40,10 @@ exports.referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -78,10 +80,10 @@ exports.referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -117,10 +119,10 @@ exports.referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -142,4 +144,4 @@ exports.referenceGeneratedDepsByArch = {
'xdg-utils (>= 1.0.2)'
]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsa0JBQWtCO1FBQ2xCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsNEJBQTRCO1FBQzVCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsMkJBQTJCO1FBQzNCLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixnQkFBZ0I7UUFDaEIsZ0JBQWdCO1FBQ2hCLGdCQUFnQjtRQUNoQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHlCQUF5QjtRQUN6QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLDRCQUE0QjtRQUM1Qix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLDJCQUEyQjtRQUMzQix3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLDRCQUE0QjtRQUM1Qix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLDJCQUEyQjtRQUMzQix3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7Q0FDRCxDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQjtJQUN0QixrQkFBa0I7SUFDbEIsV0FBVztDQUNYLENBQUM7QUFFRixvSEFBb0g7QUFDcEgsMENBQTBDO0FBQzFDLDhEQUE4RDtBQUNqRCxRQUFBLGVBQWUsR0FBRztJQUM5QixZQUFZLENBQUMseUVBQXlFO0NBQ3RGLENBQUM7QUFFVyxRQUFBLDRCQUE0QixHQUFHO0lBQzNDLE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixrQkFBa0I7UUFDbEIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx5QkFBeUI7UUFDekIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQixrQkFBa0I7UUFDbEIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyxXQUFXO1FBQ1gsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6QixVQUFVO1FBQ1YsMEJBQTBCO1FBQzFCLG9CQUFvQjtRQUNwQiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLFVBQVU7UUFDVixZQUFZO1FBQ1osMEJBQTBCO1FBQzFCLGFBQWE7UUFDYixZQUFZO1FBQ1osc0JBQXNCO0tBQ3RCO0lBQ0QsT0FBTyxFQUFFO1FBQ1IsaUJBQWlCO1FBQ2pCLHdCQUF3QjtRQUN4QiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLDJCQUEyQjtRQUMzQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGdCQUFnQjtRQUNoQixnQkFBZ0I7UUFDaEIsZ0JBQWdCO1FBQ2hCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsa0JBQWtCO1FBQ2xCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsV0FBVztRQUNYLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsa0JBQWtCO1FBQ2xCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsV0FBVztRQUNYLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtDQUNELENBQUMifQ==
+9 -7
View File
@@ -10,7 +10,9 @@ export const additionalDeps = [
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libnss3 (>= 3.26)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3', // For Breakpad crash reports.
'xdg-utils (>= 1.0.2)' // OS integration
'xdg-utils (>= 1.0.2)', // OS integration
'libgssapi-krb5-2',
'libkrb5-3',
];
// Based on https://source.chromium.org/chromium/chromium/src/+/main:chrome/installer/linux/debian/manual_recommends
@@ -38,10 +40,10 @@ export const referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -78,10 +80,10 @@ export const referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -117,10 +119,10 @@ export const referenceGeneratedDepsByArch = {
'libgbm1 (>= 17.1.0~rc2)',
'libglib2.0-0 (>= 2.12.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgssapi-krb5-2 (>= 1.17)',
'libgssapi-krb5-2',
'libgtk-3-0 (>= 3.9.10)',
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
'libkrb5-3 (>= 1.6.dfsg.2)',
'libkrb5-3',
'libnspr4 (>= 2:4.9-2~)',
'libnss3 (>= 2:3.22)',
'libnss3 (>= 3.26)',
@@ -41,8 +41,7 @@
".code-workspace",
"language-configuration.json",
"icon-theme.json",
"color-theme.json",
".code-snippets"
"color-theme.json"
],
"filenames": [
"settings.json",
@@ -54,10 +53,6 @@
"profiles.json",
"devcontainer.json",
".devcontainer.json"
],
"filenamePatterns": [
"**/User/snippets/*.json",
"**/User/profiles/*/snippets/*.json"
]
}, {
"id": "json",
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "dotnet/csharp-tmLanguage",
"repositoryUrl": "https://github.com/dotnet/csharp-tmLanguage",
"commitHash": "878aefe73f942ac68dc4a46a0f154661bcb9eff4"
"commitHash": "772323937fedd65c6dc1c8ce6ea41d97415ed7d1"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/dotnet/csharp-tmLanguage/commit/878aefe73f942ac68dc4a46a0f154661bcb9eff4",
"version": "https://github.com/dotnet/csharp-tmLanguage/commit/772323937fedd65c6dc1c8ce6ea41d97415ed7d1",
"name": "C#",
"scopeName": "source.cs",
"patterns": [
@@ -286,6 +286,9 @@
{
"include": "#nameof-expression"
},
{
"include": "#default-literal-expression"
},
{
"include": "#throw-expression"
},
@@ -298,6 +301,9 @@
{
"include": "#verbatim-interpolated-string"
},
{
"include": "#type-builtin"
},
{
"include": "#this-or-base-expression"
},
@@ -2733,6 +2739,14 @@
}
]
},
"default-literal-expression": {
"match": "(?<!\\.)\\b(default)\\b",
"captures": {
"1": {
"name": "keyword.other.default.cs"
}
}
},
"throw-expression": {
"match": "(?<!\\.)\\b(throw)\\b",
"captures": {
@@ -3673,7 +3687,7 @@
]
},
"object-creation-expression-with-parameters": {
"begin": "(?x)\n(new)\\s+\n(?<type_name>\n (?:\n (?:\n (?:(?<identifier>@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (?<name_and_type_args> # identifier + type arguments (if any)\n \\g<identifier>\\s*\n (?<type_args>\\s*<(?:[^<>]|\\g<type_args>)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g<name_and_type_args>)* | # Are there any more names being dotted into?\n (?<tuple>\\s*\\((?:[^\\(\\)]|\\g<tuple>)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n)\\s*\n(?=\\()",
"begin": "(?x)\n(new)(?:\\s+\n(?<type_name>\n (?:\n (?:\n (?:(?<identifier>@?[_[:alpha:]][_[:alnum:]]*)\\s*\\:\\:\\s*)? # alias-qualification\n (?<name_and_type_args> # identifier + type arguments (if any)\n \\g<identifier>\\s*\n (?<type_args>\\s*<(?:[^<>]|\\g<type_args>)+>\\s*)?\n )\n (?:\\s*\\.\\s*\\g<name_and_type_args>)* | # Are there any more names being dotted into?\n (?<tuple>\\s*\\((?:[^\\(\\)]|\\g<tuple>)+\\))\n )\n (?:\\s*\\?\\s*)? # nullable suffix?\n (?:\\s* # array suffix?\n \\[\n (?:\\s*,\\s*)* # commata for multi-dimensional arrays\n \\]\n \\s*\n (?:\\?)? # arrays can be nullable reference types\n \\s*\n )*\n )\n))?\\s*\n(?=\\()",
"beginCaptures": {
"1": {
"name": "keyword.other.new.cs"
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "ionide/ionide-fsgrammar",
"repositoryUrl": "https://github.com/ionide/ionide-fsgrammar",
"commitHash": "71b1ead8c99715f6c994115ebab7ee4a14cf0c59"
"commitHash": "8740e610a367c5e3f15be716acc7207655ced4cf"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/ionide/ionide-fsgrammar/commit/71b1ead8c99715f6c994115ebab7ee4a14cf0c59",
"version": "https://github.com/ionide/ionide-fsgrammar/commit/8740e610a367c5e3f15be716acc7207655ced4cf",
"name": "fsharp",
"scopeName": "source.fsharp",
"patterns": [
@@ -314,7 +314,7 @@
},
{
"match": "(?!when|and|or\\b)\\b([\\w0-9'`^._]+)",
"comments": "Here we need the \\w modifier in order to check that the words isn't blacklisted",
"comments": "Here we need the \\w modifier in order to check that the words are allowed",
"captures": {
"1": {
"name": "entity.name.type.fsharp"
@@ -1832,4 +1832,4 @@
]
}
}
}
}
+2 -2
View File
@@ -6,7 +6,7 @@
"git": {
"name": "redhat-developer/vscode-java",
"repositoryUrl": "https://github.com/redhat-developer/vscode-java",
"commitHash": "7a770ab6750b4b09173d98de14eb9792e3432b36"
"commitHash": "5fb57e8e1c5d776b21be13cd7227b25b87edf4a6"
}
},
"license": "MIT",
@@ -48,4 +48,4 @@
}
],
"version": 1
}
}
+12 -1
View File
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/redhat-developer/vscode-java/commit/7a770ab6750b4b09173d98de14eb9792e3432b36",
"version": "https://github.com/redhat-developer/vscode-java/commit/5fb57e8e1c5d776b21be13cd7227b25b87edf4a6",
"name": "Java",
"scopeName": "source.java",
"patterns": [
@@ -1378,6 +1378,17 @@
},
"properties": {
"patterns": [
{
"match": "(\\.)\\s*(new)",
"captures": {
"1": {
"name": "punctuation.separator.period.java"
},
"2": {
"name": "keyword.control.new.java"
}
}
},
{
"match": "(\\.)\\s*([a-zA-Z_$][\\w$]*)(?=\\s*\\.\\s*[a-zA-Z_$][\\w$]*)",
"captures": {
+6 -4
View File
@@ -6,16 +6,16 @@
var updateGrammar = require('vscode-grammar-updater');
function adaptJSON(grammar, name, replacementScope) {
function adaptJSON(grammar, name, replacementScope, replaceeScope = 'json') {
grammar.name = name;
grammar.scopeName = `source${replacementScope}`;
const regex = new RegExp(`\.${replaceeScope}`, 'g');
var fixScopeNames = function (rule) {
if (typeof rule.name === 'string') {
rule.name = rule.name.replace(/\.json/g, replacementScope);
rule.name = rule.name.replace(regex, replacementScope);
}
if (typeof rule.contentName === 'string') {
rule.contentName = rule.contentName.replace(/\.json/g, replacementScope);
rule.contentName = rule.contentName.replace(regex, replacementScope);
}
for (var property in rule) {
var value = rule[property];
@@ -35,3 +35,5 @@ var tsGrammarRepo = 'microsoft/vscode-JSON.tmLanguage';
updateGrammar.update(tsGrammarRepo, 'JSON.tmLanguage', './syntaxes/JSON.tmLanguage.json');
updateGrammar.update(tsGrammarRepo, 'JSON.tmLanguage', './syntaxes/JSONC.tmLanguage.json', grammar => adaptJSON(grammar, 'JSON with Comments', '.json.comments'));
updateGrammar.update(tsGrammarRepo, 'JSON.tmLanguage', './syntaxes/JSONL.tmLanguage.json', grammar => adaptJSON(grammar, 'JSON Lines', '.json.lines'));
updateGrammar.update('jeff-hykin/better-snippet-syntax', 'autogenerated/jsonc.tmLanguage.json', './syntaxes/snippets.tmLanguage.json', grammar => adaptJSON(grammar, 'Snippets', '.json.comments.snippets', 'json.comments'));
+12
View File
@@ -11,6 +11,18 @@
},
"license": "MIT",
"version": "0.0.0"
},
{
"component": {
"type": "git",
"git": {
"name": "jeff-hykin/better-snippet-syntax",
"repositoryUrl": "https://github.com/jeff-hykin/better-snippet-syntax",
"commitHash": "2b1bb124cb2b9c75c3c80eae1b8f3a043841d654"
}
},
"license": "MIT",
"version": "1.0.2"
}
],
"version": 1
+20 -1
View File
@@ -31,7 +31,7 @@
".jslintrc",
".jsonld",
".geojson",
".ipynb",
".ipynb",
".vuerc"
],
"filenames": [
@@ -77,6 +77,20 @@
],
"filenames": [],
"configuration": "./language-configuration.json"
},
{
"id": "snippets",
"aliases": [
"Code Snippets"
],
"extensions": [
".code-snippets"
],
"filenamePatterns": [
"**/User/snippets/*.json",
"**/User/profiles/*/snippets/*.json"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
@@ -94,6 +108,11 @@
"language": "jsonl",
"scopeName": "source.json.lines",
"path": "./syntaxes/JSONL.tmLanguage.json"
},
{
"language": "snippets",
"scopeName": "source.json.comments.snippets",
"path": "./syntaxes/snippets.tmLanguage.json"
}
]
},
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "jlelong/vscode-latex-basics",
"repositoryUrl": "https://github.com/jlelong/vscode-latex-basics",
"commitHash": "30adbfae9dcb0a6477584247ac477f13845d1f5f"
"commitHash": "30d04562e592305b6f6d41a539b3ccf326888aaf"
}
},
"license": "MIT",
@@ -4,7 +4,7 @@
"If you want to provide a fix or improvement, please create a pull request against the original repository.",
"Once accepted there, we are happy to receive an update request."
],
"version": "https://github.com/jlelong/vscode-latex-basics/commit/30adbfae9dcb0a6477584247ac477f13845d1f5f",
"version": "https://github.com/jlelong/vscode-latex-basics/commit/30d04562e592305b6f6d41a539b3ccf326888aaf",
"name": "LaTeX",
"scopeName": "text.tex.latex",
"patterns": [
@@ -1337,7 +1337,7 @@
]
},
{
"begin": "(\\s*\\\\begin\\{(tabular[xy*]?|xltabular|longtable|(?:long)?tabu|(?:long|tall)?tblr|NiceTabular[X*]?)\\}(\\s*\\n)?)",
"begin": "(\\s*\\\\begin\\{(tabular[xy*]?|xltabular|longtable|(?:long)?tabu|(?:long|tall)?tblr|NiceTabular[X*]?|booktabs)\\}(\\s*\\n)?)",
"captures": {
"1": {
"patterns": [
@@ -502,7 +502,7 @@
"type": "string",
"scope": "resource",
"markdownDescription": "%configuration.markdown.editor.pasteUrlAsFormattedLink.enabled%",
"default":"smart",
"default":"never",
"enum": [
"always",
"smart",
@@ -40,7 +40,7 @@ class PasteLinkEditProvider implements vscode.DocumentPasteEditProvider {
return;
}
uriEdit.label = pasteEdit.label;
uriEdit.label = pasteUrlSetting === PasteUrlAsFormattedLink.Smart ? vscode.l10n.t('Smartly Insert Link') : pasteEdit.label;
uriEdit.additionalEdit = pasteEdit.additionalEdits;
return uriEdit;
}
+1 -1
View File
@@ -6,7 +6,7 @@
"git": {
"name": "microsoft/vscode-mssql",
"repositoryUrl": "https://github.com/microsoft/vscode-mssql",
"commitHash": "cb5940297a8cef76daaf4a6b63c4968c9a12d17a"
"commitHash": "9cb3529a978ddf599bf5bdd228f21bbcfe2914f5"
}
},
"license": "MIT",
File diff suppressed because one or more lines are too long
@@ -0,0 +1,40 @@
{
// Each snippet is defined under a snippet name and has a scope, prefix, body and
// description. The scope defines in watch languages the snippet is applicable. The prefix is what is
// used to trigger the snippet and the body will be expanded and inserted.Possible variables are:
// $1, $2 for tab stops, $0 for the final cursor position, and ${1:label}, ${2:another} for placeholders.
// Placeholders with the same ids are connected.
// Example:
"MSFT Copyright Header": {
"scope": "javascript,typescript,css",
"prefix": [
"header",
"stub",
"copyright"
],
"body": [
"/*---------------------------------------------------------------------------------------------",
" * Copyright (c) Microsoft Corporation. All rights reserved.",
" * Licensed under the MIT License. See License.txt in the project root for license information.",
" *--------------------------------------------------------------------------------------------*/",
"",
"$0"
],
"description": "Insert Copyright Statement"
},
"TS -> Inject Service": {
"scope": "typescript",
"description": "Constructor Injection Pattern",
"prefix": "@inject",
"body": "@$1 private readonly _$2: ${1},$0"
},
"TS -> Event & Emitter": {
"scope": "typescript",
"prefix": "emitter",
"description": "Add emitter and event properties",
"body": [
"private readonly _onDid$1 = new Emitter<$2>();",
"readonly onDid$1: Event<$2> = this._onDid$1.event;"
],
}
}
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.81.0",
"distro": "4522c9eb8ccecb983f40d135de4b91df6f8e0312",
"version": "1.82.0",
"distro": "3278b6d258cb23d8d52820288c40fdba5e61ddd4",
"author": {
"name": "Microsoft Corporation"
},
+5 -4
View File
@@ -23,6 +23,7 @@
const Module = typeof require === 'function' ? require('module') : undefined;
const path = typeof require === 'function' ? require('path') : undefined;
const fs = typeof require === 'function' ? require('fs') : undefined;
const util = typeof require === 'function' ? require('util') : undefined;
//#region global bootstrapping
@@ -222,8 +223,8 @@
return ipcRenderer.invoke('vscode:readNlsFile', ...pathSegments);
}
if (fs && path) {
return (await fs.promises.readFile(path.join(...pathSegments))).toString();
if (fs && path && util) {
return (await util.promisify(fs.readFile)(path.join(...pathSegments))).toString();
}
throw new Error('Unsupported operation (read NLS files)');
@@ -240,8 +241,8 @@
return ipcRenderer.invoke('vscode:writeNlsFile', path, content);
}
if (fs) {
return fs.promises.writeFile(path, content);
if (fs && util) {
return util.promisify(fs.writeFile)(path, content);
}
throw new Error('Unsupported operation (write NLS files)');
@@ -391,7 +391,13 @@ export abstract class AbstractScrollableElement extends Widget {
let deltaX = e.deltaX * this._options.mouseWheelScrollSensitivity;
if (this._options.scrollPredominantAxis) {
if (Math.abs(deltaY) >= Math.abs(deltaX)) {
if (this._options.scrollYToX && deltaX + deltaY === 0) {
// when configured to map Y to X and we both see
// no dominant axis and X and Y are competing with
// identical values into opposite directions, we
// ignore the delta as we cannot make a decision then
deltaX = deltaY = 0;
} else if (Math.abs(deltaY) >= Math.abs(deltaX)) {
deltaX = 0;
} else {
deltaY = 0;
+7 -6
View File
@@ -118,7 +118,7 @@ export class AutorunObserver<TChangeSummary = any> implements IObserver, IReader
}
private _runIfNeeded() {
if (this.state === AutorunState.upToDate || this.disposed) {
if (this.state === AutorunState.upToDate) {
return;
}
@@ -128,12 +128,13 @@ export class AutorunObserver<TChangeSummary = any> implements IObserver, IReader
this.state = AutorunState.upToDate;
getLogger()?.handleAutorunTriggered(this);
try {
const changeSummary = this.changeSummary!;
this.changeSummary = this.createChangeSummary?.();
this.runFn(this, changeSummary);
if (!this.disposed) {
getLogger()?.handleAutorunTriggered(this);
const changeSummary = this.changeSummary!;
this.changeSummary = this.createChangeSummary?.();
this.runFn(this, changeSummary);
}
} finally {
// We don't want our observed observables to think that they are (not even temporarily) not being observed.
// Thus, we only unsubscribe from observables that are definitely not read anymore.
+1 -6
View File
@@ -130,11 +130,6 @@ export interface IProductConfiguration {
readonly ariaKey: string;
};
readonly sendASmile?: {
readonly reportIssueUrl: string;
readonly requestFeatureUrl: string;
};
readonly documentationUrl?: string;
readonly serverDocumentationUrl?: string;
readonly releaseNotesUrl?: string;
@@ -144,7 +139,7 @@ export interface IProductConfiguration {
readonly introductoryVideosUrl?: string;
readonly tipsAndTricksUrl?: string;
readonly newsletterSignupUrl?: string;
readonly twitterUrl?: string;
readonly youTubeUrl?: string;
readonly requestFeatureUrl?: string;
readonly reportIssueUrl?: string;
readonly reportMarketplaceIssueUrl?: string;
+51 -6
View File
@@ -6,7 +6,7 @@
import * as fs from 'fs';
import { tmpdir } from 'os';
import { promisify } from 'util';
import { ResourceQueue } from 'vs/base/common/async';
import { ResourceQueue, timeout } from 'vs/base/common/async';
import { isEqualOrParent, isRootOrDriveLetter, randomPath } from 'vs/base/common/extpath';
import { normalizeNFC } from 'vs/base/common/normalization';
import { join } from 'vs/base/common/path';
@@ -491,16 +491,24 @@ function ensureWriteOptions(options?: IWriteFileOptions): IEnsuredWriteFileOptio
/**
* A drop-in replacement for `fs.rename` that:
* - allows to move across multiple disks
* - attempts to retry the operation for certain error codes on Windows
*/
async function move(source: string, target: string): Promise<void> {
async function rename(source: string, target: string, windowsRetryTimeout: number | false = 60000 /* matches graceful-fs */): Promise<void> {
if (source === target) {
return; // simulate node.js behaviour here and do a no-op if paths match
}
try {
await Promises.rename(source, target);
if (isWindows && typeof windowsRetryTimeout === 'number') {
// On Windows, a rename can fail when either source or target
// is locked by AV software. We do leverage graceful-fs to iron
// out these issues, however in case the target file exists,
// graceful-fs will immediately return without retry for fs.rename().
await renameWithRetry(source, target, Date.now(), windowsRetryTimeout);
} else {
await promisify(fs.rename)(source, target);
}
} catch (error) {
// In two cases we fallback to classic copy and delete:
//
// 1.) The EXDEV error indicates that source and target are on different devices
@@ -518,6 +526,44 @@ async function move(source: string, target: string): Promise<void> {
}
}
async function renameWithRetry(source: string, target: string, startTime: number, retryTimeout: number, attempt = 0): Promise<void> {
try {
return await promisify(fs.rename)(source, target);
} catch (error) {
if (error.code !== 'EACCES' && error.code !== 'EPERM' && error.code !== 'EBUSY') {
throw error; // only for errors we think are temporary
}
if (Date.now() - startTime >= retryTimeout) {
console.error(`[node.js fs] rename failed after ${attempt} retries with error: ${error}`);
throw error; // give up after configurable timeout
}
if (attempt === 0) {
let abortRetry = false;
try {
const { stat } = await SymlinkSupport.stat(target);
if (!stat.isFile()) {
abortRetry = true; // if target is not a file, EPERM error may be raised and we should not attempt to retry
}
} catch (error) {
// Ignore
}
if (abortRetry) {
throw error;
}
}
// Delay with incremental backoff up to 100ms
await timeout(Math.min(100, attempt * 10));
// Attempt again
return renameWithRetry(source, target, startTime, retryTimeout, attempt + 1);
}
}
interface ICopyPayload {
readonly root: { source: string; target: string };
readonly options: { preserveSymlinks: boolean };
@@ -694,7 +740,6 @@ export const Promises = new class {
get fdatasync() { return promisify(fs.fdatasync); }
get truncate() { return promisify(fs.truncate); }
get rename() { return promisify(fs.rename); }
get copyFile() { return promisify(fs.copyFile); }
get open() { return promisify(fs.open); }
@@ -733,7 +778,7 @@ export const Promises = new class {
get rm() { return rimraf; }
get move() { return move; }
get rename() { return rename; }
get copy() { return copy; }
//#endregion
+1 -1
View File
@@ -274,7 +274,7 @@ export class SQLiteStorageDatabase implements IStorageDatabase {
try {
await Promises.unlink(path);
try {
await Promises.rename(this.toBackupPath(path), path);
await Promises.rename(this.toBackupPath(path), path, false /* no retry */);
} catch (error) {
// ignore
}
@@ -992,6 +992,29 @@ suite('observables', () => {
'event fired',
]);
});
test('dont run autorun after dispose', () => {
const log = new Log();
const myObservable = new LoggingObservableValue('myObservable', 0, log);
const d = autorun('update', reader => {
const v = myObservable.read(reader);
log.log('autorun, myObservable:' + v);
});
transaction(tx => {
myObservable.set(1, tx);
d.dispose();
});
assert.deepStrictEqual(log.getAndClearEntries(), [
'myObservable.firstObserverAdded',
'myObservable.get',
'autorun, myObservable:0',
'myObservable.set (value 1)',
'myObservable.lastObserverRemoved',
]);
});
});
export class LoggingObserver implements IObserver {
+30 -3
View File
@@ -173,7 +173,7 @@ flakySuite('PFS', function () {
assert.ok(!fs.existsSync(testDir));
});
test('copy, move and delete', async () => {
test('copy, rename and delete', async () => {
const sourceDir = FileAccess.asFileUri('vs/base/test/node/pfs/fixtures').fsPath;
const parentDir = join(tmpdir(), 'vsctests', 'pfs');
const targetDir = randomPath(parentDir);
@@ -188,7 +188,7 @@ flakySuite('PFS', function () {
assert.ok(fs.statSync(join(targetDir, 'examples')).isDirectory());
assert.ok(fs.existsSync(join(targetDir, 'examples', 'small.jxs')));
await Promises.move(targetDir, targetDir2);
await Promises.rename(targetDir, targetDir2);
assert.ok(!fs.existsSync(targetDir));
assert.ok(fs.existsSync(targetDir2));
@@ -198,7 +198,34 @@ flakySuite('PFS', function () {
assert.ok(fs.statSync(join(targetDir2, 'examples')).isDirectory());
assert.ok(fs.existsSync(join(targetDir2, 'examples', 'small.jxs')));
await Promises.move(join(targetDir2, 'index.html'), join(targetDir2, 'index_moved.html'));
await Promises.rename(join(targetDir2, 'index.html'), join(targetDir2, 'index_moved.html'));
assert.ok(!fs.existsSync(join(targetDir2, 'index.html')));
assert.ok(fs.existsSync(join(targetDir2, 'index_moved.html')));
await Promises.rm(parentDir);
assert.ok(!fs.existsSync(parentDir));
});
test('rename without retry', async () => {
const sourceDir = FileAccess.asFileUri('vs/base/test/node/pfs/fixtures').fsPath;
const parentDir = join(tmpdir(), 'vsctests', 'pfs');
const targetDir = randomPath(parentDir);
const targetDir2 = randomPath(parentDir);
await Promises.copy(sourceDir, targetDir, { preserveSymlinks: true });
await Promises.rename(targetDir, targetDir2, false);
assert.ok(!fs.existsSync(targetDir));
assert.ok(fs.existsSync(targetDir2));
assert.ok(fs.existsSync(join(targetDir2, 'index.html')));
assert.ok(fs.existsSync(join(targetDir2, 'site.css')));
assert.ok(fs.existsSync(join(targetDir2, 'examples')));
assert.ok(fs.statSync(join(targetDir2, 'examples')).isDirectory());
assert.ok(fs.existsSync(join(targetDir2, 'examples', 'small.jxs')));
await Promises.rename(join(targetDir2, 'index.html'), join(targetDir2, 'index_moved.html'), false);
assert.ok(!fs.existsSync(join(targetDir2, 'index.html')));
assert.ok(fs.existsSync(join(targetDir2, 'index_moved.html')));
@@ -90,9 +90,30 @@ export function findFocusedDiffEditor(accessor: ServicesAccessor): IDiffEditor |
return diffEditor;
}
}
if (document.activeElement) {
for (const d of diffEditors) {
const container = d.getContainerDomNode();
if (isElementOrParentOf(container, document.activeElement)) {
return d;
}
}
}
return null;
}
function isElementOrParentOf(elementOrParent: Element, element: Element): boolean {
let e: Element | null = element;
while (e) {
if (e === elementOrParent) {
return true;
}
e = e.parentElement;
}
return false;
}
CommandsRegistry.registerCommandAlias('editor.action.diffReview.next', AccessibleDiffViewerNext.id);
registerAction2(AccessibleDiffViewerNext);
@@ -63,14 +63,14 @@ function executeAction(instantiationService: IInstantiationService, editor: ICod
});
}
suite('FindController', async () => {
suite('FindController', () => {
const queryState: { [key: string]: any } = {};
let clipboardState = '';
const serviceCollection = new ServiceCollection();
serviceCollection.set(IStorageService, {
_serviceBrand: undefined,
onDidChangeTarget: Event.None,
onDidChangeValue: Event.None,
onDidChangeValue: () => Event.None,
onWillSaveState: Event.None,
get: (key: string) => queryState[key],
getBoolean: (key: string) => !!queryState[key],
@@ -495,7 +495,7 @@ suite('FindController', async () => {
});
});
suite('FindController query options persistence', async () => {
suite('FindController query options persistence', () => {
let queryState: { [key: string]: any } = {};
queryState['editor.isRegex'] = false;
queryState['editor.matchCase'] = false;
@@ -504,7 +504,7 @@ suite('FindController query options persistence', async () => {
serviceCollection.set(IStorageService, {
_serviceBrand: undefined,
onDidChangeTarget: Event.None,
onDidChangeValue: Event.None,
onDidChangeValue: () => Event.None,
onWillSaveState: Event.None,
get: (key: string) => queryState[key],
getBoolean: (key: string) => !!queryState[key],
@@ -86,7 +86,8 @@ suite('Multicursor selection', () => {
const serviceCollection = new ServiceCollection();
serviceCollection.set(IStorageService, {
_serviceBrand: undefined,
onDidChangeValue: Event.None,
onDidChangeValue: () => { throw new Error(); },
onDidChangeValue2: Event.None,
onDidChangeTarget: Event.None,
onWillSaveState: Event.None,
get: (key: string) => queryState[key],
@@ -58,10 +58,7 @@ class PersistedMenuHideState {
this._data = Object.create(null);
}
this._disposables.add(_storageService.onDidChangeValue(e => {
if (e.key !== PersistedMenuHideState._key) {
return;
}
this._disposables.add(_storageService.onDidChangeValue(StorageScope.PROFILE, PersistedMenuHideState._key, this._disposables)(() => {
if (!this._ignoreChangeEvent) {
try {
const raw = _storageService.get(PersistedMenuHideState._key, StorageScope.PROFILE, '{}');
@@ -130,7 +130,7 @@ export class BackupMainService implements IBackupMainService {
// When we have data to migrate from, move it over to the target location
if (await Promises.exists(moveFromPath)) {
try {
await Promises.rename(moveFromPath, backupPath);
await Promises.rename(moveFromPath, backupPath, false /* no retry */);
} catch (error) {
this.logService.error(`Backup: Could not move backup folder to new location: ${error.toString()}`);
}
@@ -285,7 +285,7 @@ export class BackupMainService implements IBackupMainService {
// Rename backupPath to new empty window backup path
const newEmptyWindowBackupPath = join(this.backupHome, newEmptyWindowBackupInfo.backupFolder);
try {
await Promises.rename(backupPath, newEmptyWindowBackupPath);
await Promises.rename(backupPath, newEmptyWindowBackupPath, false /* no retry */);
} catch (error) {
this.logService.error(`Backup: Could not rename backup folder: ${error.toString()}`);
return false;
@@ -4,11 +4,11 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { DISABLED_EXTENSIONS_STORAGE_PATH, IExtensionIdentifier, IExtensionManagementService, IGlobalExtensionEnablementService, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IProfileStorageValueChangeEvent, IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
export class GlobalExtensionEnablementService extends Disposable implements IGlobalExtensionEnablementService {
@@ -102,7 +102,7 @@ export class StorageManager extends Disposable {
constructor(private storageService: IStorageService) {
super();
this._register(storageService.onDidChangeValue(e => this.onDidStorageChange(e)));
this._register(storageService.onDidChangeValue(StorageScope.PROFILE, undefined, this._register(new DisposableStore()))(e => this.onDidStorageChange(e)));
}
get(key: string, scope: StorageScope): IExtensionIdentifier[] {
@@ -133,19 +133,17 @@ export class StorageManager extends Disposable {
}
}
private onDidStorageChange(storageChangeEvent: IStorageValueChangeEvent): void {
if (storageChangeEvent.scope === StorageScope.PROFILE) {
if (!isUndefinedOrNull(this.storage[storageChangeEvent.key])) {
const newValue = this._get(storageChangeEvent.key, storageChangeEvent.scope);
if (newValue !== this.storage[storageChangeEvent.key]) {
const oldValues = this.get(storageChangeEvent.key, storageChangeEvent.scope);
delete this.storage[storageChangeEvent.key];
const newValues = this.get(storageChangeEvent.key, storageChangeEvent.scope);
const added = oldValues.filter(oldValue => !newValues.some(newValue => areSameExtensions(oldValue, newValue)));
const removed = newValues.filter(newValue => !oldValues.some(oldValue => areSameExtensions(oldValue, newValue)));
if (added.length || removed.length) {
this._onDidChange.fire([...added, ...removed]);
}
private onDidStorageChange(storageChangeEvent: IProfileStorageValueChangeEvent): void {
if (!isUndefinedOrNull(this.storage[storageChangeEvent.key])) {
const newValue = this._get(storageChangeEvent.key, storageChangeEvent.scope);
if (newValue !== this.storage[storageChangeEvent.key]) {
const oldValues = this.get(storageChangeEvent.key, storageChangeEvent.scope);
delete this.storage[storageChangeEvent.key];
const newValues = this.get(storageChangeEvent.key, storageChangeEvent.scope);
const added = oldValues.filter(oldValue => !newValues.some(newValue => areSameExtensions(oldValue, newValue)));
const removed = newValues.filter(newValue => !oldValues.some(oldValue => areSameExtensions(oldValue, newValue)));
if (added.length || removed.length) {
this._onDidChange.fire([...added, ...removed]);
}
}
}
@@ -5,8 +5,8 @@
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { IProfileStorageValueChangeEvent, IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { adoptToGalleryExtensionId, areSameExtensions, getExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { IProductService } from 'vs/platform/product/common/productService';
import { distinct } from 'vs/base/common/arrays';
@@ -103,13 +103,10 @@ export class ExtensionStorageService extends Disposable implements IExtensionSto
) {
super();
this.extensionsWithKeysForSync = ExtensionStorageService.readAllExtensionsWithKeysForSync(storageService);
this._register(this.storageService.onDidChangeValue(e => this.onDidChangeStorageValue(e)));
this._register(this.storageService.onDidChangeValue(StorageScope.PROFILE, undefined, this._register(new DisposableStore()))(e => this.onDidChangeStorageValue(e)));
}
private onDidChangeStorageValue(e: IStorageValueChangeEvent): void {
if (e.scope !== StorageScope.PROFILE) {
return;
}
private onDidChangeStorageValue(e: IProfileStorageValueChangeEvent): void {
// State of extension with keys for sync has changed
if (this.extensionsWithKeysForSync.has(e.key.toLowerCase())) {
@@ -7,7 +7,6 @@ import { Promises } from 'vs/base/common/async';
import { getErrorMessage } from 'vs/base/common/errors';
import { Disposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { isWindows } from 'vs/base/common/platform';
import { joinPath } from 'vs/base/common/resources';
import * as semver from 'vs/base/common/semver/semver';
import { isBoolean } from 'vs/base/common/types';
@@ -129,7 +128,7 @@ export class ExtensionsDownloader extends Disposable {
try {
// Rename temp location to original
await this.rename(tempLocation, location, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */);
await FSPromises.rename(tempLocation.fsPath, location.fsPath, 2 * 60 * 1000 /* Retry for 2 minutes */);
} catch (error) {
try {
await this.fileService.del(tempLocation);
@@ -148,18 +147,6 @@ export class ExtensionsDownloader extends Disposable {
await this.fileService.del(location);
}
private async rename(from: URI, to: URI, retryUntil: number): Promise<void> {
try {
await FSPromises.rename(from.fsPath, to.fsPath);
} catch (error) {
if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) {
this.logService.info(`Failed renaming ${from} to ${to} with 'EPERM' error. Trying again...`);
return this.rename(from, to, retryUntil);
}
throw error;
}
}
private async cleanUp(): Promise<void> {
try {
if (!(await this.fileService.exists(this.extensionsDownloadDir))) {
@@ -15,7 +15,6 @@ import { Disposable } from 'vs/base/common/lifecycle';
import { ResourceSet } from 'vs/base/common/map';
import { Schemas } from 'vs/base/common/network';
import * as path from 'vs/base/common/path';
import { isWindows } from 'vs/base/common/platform';
import { joinPath } from 'vs/base/common/resources';
import * as semver from 'vs/base/common/semver/semver';
import { isBoolean, isUndefined } from 'vs/base/common/types';
@@ -508,7 +507,7 @@ export class ExtensionsScanner extends Disposable {
// Rename
try {
this.logService.trace(`Started renaming the extension from ${tempLocation.fsPath} to ${extensionLocation.fsPath}`);
await this.rename(extensionKey, tempLocation.fsPath, extensionLocation.fsPath, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */);
await this.rename(tempLocation.fsPath, extensionLocation.fsPath);
this.logService.info('Renamed to', extensionLocation.fsPath);
} catch (error) {
if (error.code === 'ENOTEMPTY') {
@@ -606,7 +605,7 @@ export class ExtensionsScanner extends Disposable {
private async deleteExtensionFromLocation(id: string, location: URI, type: string): Promise<void> {
this.logService.trace(`Deleting ${type} extension from disk`, id, location.fsPath);
const renamedLocation = this.uriIdentityService.extUri.joinPath(this.uriIdentityService.extUri.dirname(location), `${this.uriIdentityService.extUri.basename(location)}.${hash(generateUuid()).toString(16)}${DELETED_FOLDER_POSTFIX}`);
await this.rename({ id }, location.fsPath, renamedLocation.fsPath, Date.now() + (2 * 60 * 1000) /* Retry for 2 minutes */);
await this.rename(location.fsPath, renamedLocation.fsPath);
await this.fileService.del(renamedLocation, { recursive: true });
this.logService.info(`Deleted ${type} extension from disk`, id, location.fsPath);
}
@@ -643,14 +642,10 @@ export class ExtensionsScanner extends Disposable {
});
}
private async rename(identifier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise<void> {
private async rename(extractPath: string, renamePath: string): Promise<void> {
try {
await pfs.Promises.rename(extractPath, renamePath);
await pfs.Promises.rename(extractPath, renamePath, 2 * 60 * 1000 /* Retry for 2 minutes */);
} catch (error) {
if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) {
this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identifier.id);
return this.rename(identifier, extractPath, renamePath, retryUntil);
}
throw new ExtensionManagementError(error.message || nls.localize('renameError', "Unknown error while renaming {0} to {1}", extractPath, renamePath), error.code || ExtensionManagementErrorCode.Rename);
}
}
@@ -640,8 +640,8 @@ export class DiskFileSystemProvider extends AbstractDiskFileSystemProvider imple
// Validate the move operation can perform
await this.validateMoveCopy(from, to, 'move', opts.overwrite);
// Move
await Promises.move(fromFilePath, toFilePath);
// Rename
await Promises.rename(fromFilePath, toFilePath);
} catch (error) {
// Rewrite some typical errors that can happen especially around symlinks
@@ -252,7 +252,7 @@ import { FileAccess } from 'vs/base/common/network';
// Move file
changeFuture = awaitEvent(watcher, filePath, FileChangeType.DELETED);
await Promises.move(filePath, `${filePath}-moved`);
await Promises.rename(filePath, `${filePath}-moved`);
await changeFuture;
});
@@ -125,9 +125,9 @@ export class Menubar {
this.fallbackMenuHandlers['workbench.action.clearRecentFiles'] = () => this.workspacesHistoryMainService.clearRecentlyOpened();
// Help Menu Items
const twitterUrl = this.productService.twitterUrl;
if (twitterUrl) {
this.fallbackMenuHandlers['workbench.action.openTwitterUrl'] = () => this.openUrl(twitterUrl, 'openTwitterUrl');
const youTubeUrl = this.productService.youTubeUrl;
if (youTubeUrl) {
this.fallbackMenuHandlers['workbench.action.openYouTubeUrl'] = () => this.openUrl(youTubeUrl, 'openYouTubeUrl');
}
const requestFeatureUrl = this.productService.requestFeatureUrl;
+1 -1
View File
@@ -58,7 +58,7 @@ else {
// Running out of sources
if (Object.keys(product).length === 0) {
Object.assign(product, {
version: '1.80.0-dev',
version: '1.82.0-dev',
nameShort: 'Code - OSS Dev',
nameLong: 'Code - OSS Dev',
applicationName: 'code-oss',
+2 -2
View File
@@ -5,7 +5,7 @@
import * as os from 'os';
import * as cp from 'child_process';
import { promises as fs } from 'fs';
import { Promises } from 'vs/base/node/pfs';
import * as path from 'path';
let hasWSLFeaturePromise: Promise<boolean> | undefined;
@@ -33,7 +33,7 @@ async function testWSLFeatureInstalled(): Promise<boolean> {
const dllPath = getLxssManagerDllPath();
if (dllPath) {
try {
if ((await fs.stat(dllPath)).isFile()) {
if ((await Promises.stat(dllPath)).isFile()) {
return true;
}
} catch (e) {
+6 -11
View File
@@ -9,7 +9,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
import { IStorageService, InMemoryStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Emitter, Event } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
export const ISecretStorageService = createDecorator<ISecretStorageService>('secretStorageService');
@@ -38,7 +38,7 @@ export abstract class BaseSecretStorageService implements ISecretStorageService
private _type: 'in-memory' | 'persisted' | 'unknown' = 'unknown';
private _onDidChangeValueDisposable: IDisposable | undefined;
private readonly _onDidChangeValueDisposable = new DisposableStore();
constructor(
@IStorageService private _storageService: IStorageService,
@@ -127,15 +127,10 @@ export abstract class BaseSecretStorageService implements ISecretStorageService
storageService = new InMemoryStorageService();
}
this._onDidChangeValueDisposable?.dispose();
this._onDidChangeValueDisposable = storageService.onDidChangeValue(e => {
// We only care about changes to the application scope since SecretStorage
// only stores secrets in the application scope but this seems to fire
// 2 events. Once for APP scope and once for PROFILE scope. ref #188460
if (e.scope === StorageScope.APPLICATION) {
this.onDidChangeValue(e.key);
}
});
this._onDidChangeValueDisposable.clear();
this._onDidChangeValueDisposable.add(storageService.onDidChangeValue(StorageScope.APPLICATION, undefined, this._onDidChangeValueDisposable)(e => {
this.onDidChangeValue(e.key);
}));
return storageService;
}
+30 -4
View File
@@ -5,7 +5,7 @@
import { Promises, RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
import { Emitter, Event, PauseableEmitter } from 'vs/base/common/event';
import { Disposable, dispose, MutableDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, dispose, MutableDisposable } from 'vs/base/common/lifecycle';
import { mark } from 'vs/base/common/performance';
import { isUndefinedOrNull } from 'vs/base/common/types';
import { InMemoryStorageDatabase, IStorage, IStorageChangeEvent, Storage, StorageHint, StorageValue } from 'vs/base/parts/storage/common/storage';
@@ -42,14 +42,34 @@ export interface IStorageEntry {
readonly target: StorageTarget;
}
export interface IWorkspaceStorageValueChangeEvent extends IStorageValueChangeEvent {
readonly scope: StorageScope.WORKSPACE;
}
export interface IProfileStorageValueChangeEvent extends IStorageValueChangeEvent {
readonly scope: StorageScope.PROFILE;
}
export interface IApplicationStorageValueChangeEvent extends IStorageValueChangeEvent {
readonly scope: StorageScope.APPLICATION;
}
export interface IStorageService {
readonly _serviceBrand: undefined;
/**
* Emitted whenever data is updated or deleted.
* Emitted whenever data is updated or deleted on the given
* scope and optional key.
*
* @param scope the `StorageScope` to listen to changes
* @param key the optional key to filter for or all keys of
* the scope if `undefined`
*/
readonly onDidChangeValue: Event<IStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event<IWorkspaceStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event<IProfileStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event<IApplicationStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event<IStorageValueChangeEvent>;
/**
* Emitted whenever target of a storage entry changes.
@@ -294,7 +314,6 @@ export abstract class AbstractStorageService extends Disposable implements IStor
private static DEFAULT_FLUSH_INTERVAL = 60 * 1000; // every minute
private readonly _onDidChangeValue = this._register(new PauseableEmitter<IStorageValueChangeEvent>());
readonly onDidChangeValue = this._onDidChangeValue.event;
private readonly _onDidChangeTarget = this._register(new PauseableEmitter<IStorageTargetChangeEvent>());
readonly onDidChangeTarget = this._onDidChangeTarget.event;
@@ -311,6 +330,13 @@ export abstract class AbstractStorageService extends Disposable implements IStor
super();
}
onDidChangeValue(scope: StorageScope.WORKSPACE, key: string | undefined, disposable: DisposableStore): Event<IWorkspaceStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope.PROFILE, key: string | undefined, disposable: DisposableStore): Event<IProfileStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope.APPLICATION, key: string | undefined, disposable: DisposableStore): Event<IApplicationStorageValueChangeEvent>;
onDidChangeValue(scope: StorageScope, key: string | undefined, disposable: DisposableStore): Event<IStorageValueChangeEvent> {
return Event.filter(this._onDidChangeValue.event, e => e.scope === scope && (key === undefined || e.key === key), disposable);
}
private doFlushWhenIdle(): void {
this.runFlushWhenIdle.value = runWhenIdle(() => {
if (this.shouldFlushWhenIdle()) {
@@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { deepStrictEqual, ok, strictEqual } from 'assert';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { InMemoryStorageService, IStorageService, IStorageTargetChangeEvent, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
export function createSuite<T extends IStorageService>(params: { setup: () => Promise<T>; teardown: (service: T) => Promise<void> }): void {
@@ -32,7 +33,7 @@ export function createSuite<T extends IStorageService>(params: { setup: () => Pr
test('Storage change source', () => {
const storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storageService.onDidChangeValue(e => storageValueChangeEvents.push(e));
storageService.onDidChangeValue(StorageScope.WORKSPACE, undefined, new DisposableStore())(e => storageValueChangeEvents.push(e));
// Explicit external source
storageService.storeAll([{ key: 'testExternalChange', value: 'foobar', scope: StorageScope.WORKSPACE, target: StorageTarget.MACHINE }], true);
@@ -49,9 +50,34 @@ export function createSuite<T extends IStorageService>(params: { setup: () => Pr
strictEqual(storageValueChangeEvent?.external, false);
});
test('Storage change event scope (all keys)', () => {
const storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storageService.onDidChangeValue(StorageScope.WORKSPACE, undefined, new DisposableStore())(e => storageValueChangeEvents.push(e));
storageService.store('testChange', 'foobar', StorageScope.WORKSPACE, StorageTarget.MACHINE);
storageService.store('testChange2', 'foobar', StorageScope.WORKSPACE, StorageTarget.MACHINE);
storageService.store('testChange', 'foobar', StorageScope.APPLICATION, StorageTarget.MACHINE);
storageService.store('testChange', 'foobar', StorageScope.PROFILE, StorageTarget.MACHINE);
storageService.store('testChange2', 'foobar', StorageScope.PROFILE, StorageTarget.MACHINE);
strictEqual(storageValueChangeEvents.length, 2);
});
test('Storage change event scope (specific key)', () => {
const storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storageService.onDidChangeValue(StorageScope.WORKSPACE, 'testChange', new DisposableStore())(e => storageValueChangeEvents.push(e));
storageService.store('testChange', 'foobar', StorageScope.WORKSPACE, StorageTarget.MACHINE);
storageService.store('testChange', 'foobar', StorageScope.PROFILE, StorageTarget.USER);
storageService.store('testChange', 'foobar', StorageScope.APPLICATION, StorageTarget.MACHINE);
storageService.store('testChange2', 'foobar', StorageScope.WORKSPACE, StorageTarget.MACHINE);
const storageValueChangeEvent = storageValueChangeEvents.find(e => e.key === 'testChange');
ok(storageValueChangeEvent);
strictEqual(storageValueChangeEvents.length, 1);
});
function storeData(scope: StorageScope): void {
let storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storageService.onDidChangeValue(e => storageValueChangeEvents.push(e));
storageService.onDidChangeValue(scope, undefined, new DisposableStore())(e => storageValueChangeEvents.push(e));
strictEqual(storageService.get('test.get', scope, 'foobar'), 'foobar');
strictEqual(storageService.get('test.get', scope, ''), '');
@@ -127,7 +153,7 @@ export function createSuite<T extends IStorageService>(params: { setup: () => Pr
function removeData(scope: StorageScope): void {
const storageValueChangeEvents: IStorageValueChangeEvent[] = [];
storageService.onDidChangeValue(e => storageValueChangeEvents.push(e));
storageService.onDidChangeValue(scope, undefined, new DisposableStore())(e => storageValueChangeEvents.push(e));
storageService.store('test.remove', 'foobar', scope, StorageTarget.MACHINE);
strictEqual('foobar', storageService.get('test.remove', scope, (undefined)!));
@@ -143,9 +169,6 @@ export function createSuite<T extends IStorageService>(params: { setup: () => Pr
let storageTargetEvent: IStorageTargetChangeEvent | undefined = undefined;
storageService.onDidChangeTarget(e => storageTargetEvent = e);
let storageValueChangeEvent: IStorageValueChangeEvent | undefined = undefined;
storageService.onDidChangeValue(e => storageValueChangeEvent = e);
// Empty
for (const scope of [StorageScope.WORKSPACE, StorageScope.PROFILE, StorageScope.APPLICATION]) {
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
@@ -153,8 +176,12 @@ export function createSuite<T extends IStorageService>(params: { setup: () => Pr
}
}
let storageValueChangeEvent: IStorageValueChangeEvent | undefined = undefined;
// Add values
for (const scope of [StorageScope.WORKSPACE, StorageScope.PROFILE, StorageScope.APPLICATION]) {
storageService.onDidChangeValue(scope, undefined, new DisposableStore())(e => storageValueChangeEvent = e);
for (const target of [StorageTarget.MACHINE, StorageTarget.USER]) {
storageTargetEvent = Object.create(null);
storageValueChangeEvent = Object.create(null);
@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import { exec } from 'child_process';
import { promises as fs } from 'fs';
import { timeout } from 'vs/base/common/async';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
@@ -213,9 +212,9 @@ export class TerminalProcess extends Disposable implements ITerminalChildProcess
}
if (injection.filesToCopy) {
for (const f of injection.filesToCopy) {
await fs.mkdir(path.dirname(f.dest), { recursive: true });
await Promises.mkdir(path.dirname(f.dest), { recursive: true });
try {
await fs.copyFile(f.source, f.dest);
await Promises.copyFile(f.source, f.dest);
} catch {
// Swallow error, this should only happen when multiple users are on the same
// machine. Since the shell integration scripts rarely change, plus the other user
@@ -137,7 +137,7 @@ export class Win32UpdateService extends AbstractUpdateService {
return this.requestService.request({ url }, CancellationToken.None)
.then(context => this.fileService.writeFile(URI.file(downloadPath), context.stream))
.then(hash ? () => checksum(downloadPath, update.hash) : () => undefined)
.then(() => pfs.Promises.rename(downloadPath, updatePackagePath))
.then(() => pfs.Promises.rename(downloadPath, updatePackagePath, false /* no retry */))
.then(() => updatePackagePath);
});
}).then(packagePath => {
@@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isWeb } from 'vs/base/common/platform';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IApplicationStorageValueChangeEvent, IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ALL_SYNC_RESOURCES, getEnablementKey, IUserDataSyncEnablementService, IUserDataSyncStoreManagementService, SyncResource } from 'vs/platform/userDataSync/common/userDataSync';
@@ -36,7 +36,7 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
@IUserDataSyncStoreManagementService private readonly userDataSyncStoreManagementService: IUserDataSyncStoreManagementService,
) {
super();
this._register(storageService.onDidChangeValue(e => this.onDidStorageChange(e)));
this._register(storageService.onDidChangeValue(StorageScope.APPLICATION, undefined, this._register(new DisposableStore()))(e => this.onDidStorageChange(e)));
}
isEnabled(): boolean {
@@ -80,11 +80,7 @@ export class UserDataSyncEnablementService extends Disposable implements IUserDa
this.storageService.store(resourceEnablementKey, enabled, StorageScope.APPLICATION, isWeb ? StorageTarget.USER /* sync in web */ : StorageTarget.MACHINE);
}
private onDidStorageChange(storageChangeEvent: IStorageValueChangeEvent): void {
if (storageChangeEvent.scope !== StorageScope.APPLICATION) {
return;
}
private onDidStorageChange(storageChangeEvent: IApplicationStorageValueChangeEvent): void {
if (enablementKey === storageChangeEvent.key) {
this._onDidChangeEnablement.fire(this.isEnabled());
return;
@@ -7,7 +7,7 @@ import { CancelablePromise, createCancelablePromise, timeout } from 'vs/base/com
import { CancellationToken } from 'vs/base/common/cancellation';
import { getErrorMessage, isCancellationError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { Mimes } from 'vs/base/common/mime';
import { isWeb } from 'vs/base/common/platform';
import { ConfigurationSyncStore } from 'vs/base/common/product';
@@ -58,7 +58,8 @@ export abstract class AbstractUserDataSyncStoreManagementService extends Disposa
) {
super();
this.updateUserDataSyncStore();
this._register(Event.filter(storageService.onDidChangeValue, e => e.key === SYNC_SERVICE_URL_TYPE && e.scope === StorageScope.APPLICATION && this.userDataSyncStoreType !== this.userDataSyncStore?.type)(() => this.updateUserDataSyncStore()));
const disposable = this._register(new DisposableStore());
this._register(Event.filter(storageService.onDidChangeValue(StorageScope.APPLICATION, SYNC_SERVICE_URL_TYPE, disposable), () => this.userDataSyncStoreType !== this.userDataSyncStore?.type, disposable)(() => this.updateUserDataSyncStore()));
}
protected updateUserDataSyncStore(): void {
+1
View File
@@ -273,6 +273,7 @@ export interface IWindowConfiguration {
export interface IOSConfiguration {
readonly release: string;
readonly hostname: string;
readonly arch: string;
}
export interface INativeWindowConfiguration extends IWindowConfiguration, NativeParsedArgs, ISandboxConfiguration {
@@ -6,7 +6,7 @@
import { app, BrowserWindow, WebContents, shell } from 'electron';
import { Promises } from 'vs/base/node/pfs';
import { addUNCHostToAllowlist } from 'vs/base/node/unc';
import { hostname, release } from 'os';
import { hostname, release, arch } from 'os';
import { coalesce, distinct, firstOrDefault } from 'vs/base/common/arrays';
import { CancellationToken } from 'vs/base/common/cancellation';
import { CharCode } from 'vs/base/common/charCode';
@@ -1424,7 +1424,7 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
product,
isInitialStartup: options.initialStartup,
perfMarks: getMarks(),
os: { release: release(), hostname: hostname() },
os: { release: release(), hostname: hostname(), arch: arch() },
zoomLevel: typeof windowConfig?.zoomLevel === 'number' ? windowConfig.zoomLevel : undefined,
autoDetectHighContrast: windowConfig?.autoDetectHighContrast ?? true,
+7 -6
View File
@@ -3,7 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { promises as fsp, createReadStream } from 'fs';
import { createReadStream } from 'fs';
import { Promises } from 'vs/base/node/pfs';
import * as path from 'path';
import * as http from 'http';
import * as url from 'url';
@@ -55,7 +56,7 @@ export const enum CacheControl {
*/
export async function serveFile(filePath: string, cacheControl: CacheControl, logService: ILogService, req: http.IncomingMessage, res: http.ServerResponse, responseHeaders: Record<string, string>): Promise<void> {
try {
const stat = await fsp.stat(filePath); // throws an error if file doesn't exist
const stat = await Promises.stat(filePath); // throws an error if file doesn't exist
if (cacheControl === CacheControl.ETAG) {
// Check if file modified since
@@ -318,7 +319,7 @@ export class WebClientServer {
if (!this._environmentService.isBuilt) {
try {
const productOverrides = JSON.parse((await fsp.readFile(join(APP_ROOT, 'product.overrides.json'))).toString());
const productOverrides = JSON.parse((await Promises.readFile(join(APP_ROOT, 'product.overrides.json'))).toString());
Object.assign(productConfiguration, productOverrides);
} catch (err) {/* Ignore Error */ }
}
@@ -346,7 +347,7 @@ export class WebClientServer {
if (useTestResolver) {
const bundledExtensions: { extensionPath: string; packageJSON: IExtensionManifest }[] = [];
for (const extensionPath of ['vscode-test-resolver', 'github-authentication']) {
const packageJSON = JSON.parse((await fsp.readFile(FileAccess.asFileUri(`${builtinExtensionsPath}/${extensionPath}/package.json`).fsPath)).toString());
const packageJSON = JSON.parse((await Promises.readFile(FileAccess.asFileUri(`${builtinExtensionsPath}/${extensionPath}/package.json`).fsPath)).toString());
bundledExtensions.push({ extensionPath, packageJSON });
}
values['WORKBENCH_BUILTIN_EXTENSIONS'] = asJSON(bundledExtensions);
@@ -354,7 +355,7 @@ export class WebClientServer {
let data;
try {
const workbenchTemplate = (await fsp.readFile(filePath)).toString();
const workbenchTemplate = (await Promises.readFile(filePath)).toString();
data = workbenchTemplate.replace(/\{\{([^}]+)\}\}/g, (_, key) => values[key] ?? 'undefined');
} catch (e) {
res.writeHead(404, { 'Content-Type': 'text/plain' });
@@ -421,7 +422,7 @@ export class WebClientServer {
*/
private async _handleCallback(res: http.ServerResponse): Promise<void> {
const filePath = FileAccess.asFileUri('vs/code/browser/workbench/callback.html').fsPath;
const data = (await fsp.readFile(filePath)).toString();
const data = (await Promises.readFile(filePath)).toString();
const cspDirectives = [
'default-src \'self\';',
'img-src \'self\' https: data: blob:;',
@@ -6,7 +6,7 @@
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { MainThreadStorageShape, MainContext, ExtHostStorageShape, ExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer, IExtHostContext } from 'vs/workbench/services/extensions/common/extHostCustomers';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { isWeb } from 'vs/base/common/platform';
import { IExtensionIdWithVersion, IExtensionStorageService } from 'vs/platform/extensionManagement/common/extensionStorage';
import { migrateExtensionStorage } from 'vs/workbench/services/extensions/common/extensionStorageMigration';
@@ -17,7 +17,7 @@ import { ILogService } from 'vs/platform/log/common/log';
export class MainThreadStorage implements MainThreadStorageShape {
private readonly _proxy: ExtHostStorageShape;
private readonly _storageListener: IDisposable;
private readonly _storageListener = new DisposableStore();
private readonly _sharedStorageKeysToWatch: Map<string, boolean> = new Map<string, boolean>();
constructor(
@@ -29,15 +29,14 @@ export class MainThreadStorage implements MainThreadStorageShape {
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostStorage);
this._storageListener = this._storageService.onDidChangeValue(e => {
const shared = e.scope === StorageScope.PROFILE;
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
const rawState = this._extensionStorageService.getExtensionStateRaw(e.key, shared);
this._storageListener.add(this._storageService.onDidChangeValue(StorageScope.PROFILE, undefined, this._storageListener)(e => {
if (this._sharedStorageKeysToWatch.has(e.key)) {
const rawState = this._extensionStorageService.getExtensionStateRaw(e.key, true);
if (typeof rawState === 'string') {
this._proxy.$acceptValue(shared, e.key, rawState);
this._proxy.$acceptValue(true, e.key, rawState);
}
}
});
}));
}
dispose(): void {
+1 -1
View File
@@ -18,7 +18,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { LogLevel, createHttpPatch, createProxyResolver, createTlsPatch, ProxySupportSetting, ProxyAgentParams, createNetPatch } from '@vscode/proxy-agent';
const systemCertificatesV2Default = true;
const systemCertificatesV2Default = false;
export function connectProxyResolver(
extHostWorkspace: IExtHostWorkspaceProvider,
+11 -11
View File
@@ -177,18 +177,18 @@ class OpenNewsletterSignupUrlAction extends Action2 {
}
}
class OpenTwitterUrlAction extends Action2 {
class OpenYouTubeUrlAction extends Action2 {
static readonly ID = 'workbench.action.openTwitterUrl';
static readonly AVAILABLE = !!product.twitterUrl;
static readonly ID = 'workbench.action.openYouTubeUrl';
static readonly AVAILABLE = !!product.youTubeUrl;
constructor() {
super({
id: OpenTwitterUrlAction.ID,
id: OpenYouTubeUrlAction.ID,
title: {
value: localize('openTwitterUrl', "Join Us on Twitter"),
mnemonicTitle: localize({ key: 'miTwitter', comment: ['&& denotes a mnemonic'] }, "&&Join Us on Twitter"),
original: 'Join Us on Twitter'
value: localize('openYouTubeUrl', "Join Us on YouTube"),
mnemonicTitle: localize({ key: 'miYouTube', comment: ['&& denotes a mnemonic'] }, "&&Join Us on YouTube"),
original: 'Join Us on YouTube'
},
category: Categories.Help,
f1: true,
@@ -204,8 +204,8 @@ class OpenTwitterUrlAction extends Action2 {
const productService = accessor.get(IProductService);
const openerService = accessor.get(IOpenerService);
if (productService.twitterUrl) {
openerService.open(URI.parse(productService.twitterUrl));
if (productService.youTubeUrl) {
openerService.open(URI.parse(productService.youTubeUrl));
}
}
}
@@ -337,8 +337,8 @@ if (OpenNewsletterSignupUrlAction.AVAILABLE) {
registerAction2(OpenNewsletterSignupUrlAction);
}
if (OpenTwitterUrlAction.AVAILABLE) {
registerAction2(OpenTwitterUrlAction);
if (OpenYouTubeUrlAction.AVAILABLE) {
registerAction2(OpenYouTubeUrlAction);
}
if (OpenRequestFeatureUrlAction.AVAILABLE) {
+1 -1
View File
@@ -2469,7 +2469,7 @@ class LayoutStateModel extends Disposable {
}
// Register for runtime key changes
this._register(this.storageService.onDidChangeValue(storageChangeEvent => {
this._register(this.storageService.onDidChangeValue(StorageScope.PROFILE, undefined, this._register(new DisposableStore()))(storageChangeEvent => {
let key: keyof typeof LayoutStateKeys;
for (key in LayoutStateKeys) {
const stateKey = LayoutStateKeys[key] as WorkbenchLayoutStateKey<StorageKeyType>;
@@ -19,7 +19,7 @@ import { ACTIVITY_BAR_BACKGROUND, ACTIVITY_BAR_BORDER, ACTIVITY_BAR_FOREGROUND,
import { contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { CompositeBar, ICompositeBarItem, CompositeDragAndDrop } from 'vs/workbench/browser/parts/compositeBar';
import { Dimension, createCSSRule, asCSSUrl, addDisposableListener, EventType, isAncestor } from 'vs/base/browser/dom';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget, IProfileStorageValueChangeEvent } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ToggleCompositePinnedAction, ICompositeBarColors, ActivityAction, ICompositeActivity, IActivityHoverOptions, ToggleCompositeBadgeAction } from 'vs/workbench/browser/parts/compositeBarActions';
@@ -247,7 +247,7 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
disposables.clear();
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedViewContainers(), this, disposables);
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
this.storageService.onDidChangeValue(StorageScope.PROFILE, ActivitybarPart.PINNED_VIEW_CONTAINERS, disposables)(e => this.onDidStorageValueChange(e), this, disposables);
}));
// Register for configuration changes
@@ -807,9 +807,8 @@ export class ActivitybarPart extends Part implements IPaneCompositeSelectorPart
return this.viewDescriptorService.getViewContainersByLocation(this.location);
}
private onDidStorageValueChange(e: IStorageValueChangeEvent): void {
if (e.key === ActivitybarPart.PINNED_VIEW_CONTAINERS && e.scope === StorageScope.PROFILE
&& this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) {
private onDidStorageValueChange(e: IProfileStorageValueChangeEvent): void {
if (this.pinnedViewContainersValue !== this.getStoredPinnedViewContainersValue() /* This checks if current window changed the value or not */) {
this._pinnedViewContainersValue = undefined;
this._cachedViewContainers = undefined;
@@ -31,6 +31,7 @@ export const DEFAULT_EDITOR_PART_OPTIONS: IEditorPartOptions = {
tabSizingFixedMinWidth: 50,
tabSizingFixedMaxWidth: 160,
pinnedTabSizing: 'normal',
preventPinnedEditorClose: 'keyboardAndMouse',
titleScrollbarSizing: 'default',
focusRecentEditorAfterClose: true,
showIcons: true,
@@ -783,15 +783,17 @@ function registerCloseEditorCommands() {
const editorGroupsService = accessor.get(IEditorGroupsService);
const editorService = accessor.get(IEditorService);
let keepStickyEditors = true;
let keepStickyEditors: boolean | undefined = undefined;
if (forceCloseStickyEditors) {
keepStickyEditors = false; // explicitly close sticky editors
} else if (resourceOrContext || context) {
keepStickyEditors = false; // we have a context, as such this command was used e.g. from the tab context menu
} else {
keepStickyEditors = editorGroupsService.partOptions.preventPinnedEditorClose === 'keyboard' || editorGroupsService.partOptions.preventPinnedEditorClose === 'keyboardAndMouse'; // respect setting otherwise
}
// Without context: skip over sticky editor and select next if active editor is sticky
if (keepStickyEditors && !resourceOrContext && !context) {
// Skip over sticky editor and select next if we are configured to do so
if (keepStickyEditors) {
const activeGroup = editorGroupsService.activeGroup;
const activeEditor = activeGroup.activeEditor;
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/notabstitlecontrol';
import { EditorResourceAccessor, Verbosity, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor';
import { EditorResourceAccessor, Verbosity, IEditorPartOptions, SideBySideEditor, preventEditorClose, EditorCloseMethod } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { TitleControl, IToolbarActions, ITitleControlDimensions } from 'vs/workbench/browser/parts/editor/titleControl';
import { ResourceLabel, IResourceLabel } from 'vs/workbench/browser/labels';
@@ -105,7 +105,9 @@ export class NoTabsTitleControl extends TitleControl {
if (e.button === 1 /* Middle Button */ && this.group.activeEditor) {
EventHelper.stop(e, true /* for https://github.com/microsoft/vscode/issues/56715 */);
this.group.closeEditor(this.group.activeEditor);
if (!preventEditorClose(this.group, this.group.activeEditor, EditorCloseMethod.MOUSE, this.accessor.partOptions)) {
this.group.closeEditor(this.group.activeEditor);
}
}
}
@@ -6,7 +6,7 @@
import 'vs/css!./media/tabstitlecontrol';
import { isMacintosh, isWindows } from 'vs/base/common/platform';
import { shorten } from 'vs/base/common/labels';
import { EditorResourceAccessor, GroupIdentifier, Verbosity, IEditorPartOptions, SideBySideEditor, DEFAULT_EDITOR_ASSOCIATION, EditorInputCapabilities, IUntypedEditorInput } from 'vs/workbench/common/editor';
import { EditorResourceAccessor, GroupIdentifier, Verbosity, IEditorPartOptions, SideBySideEditor, DEFAULT_EDITOR_ASSOCIATION, EditorInputCapabilities, IUntypedEditorInput, preventEditorClose, EditorCloseMethod } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { computeEditorAriaLabel } from 'vs/workbench/browser/editor';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
@@ -847,10 +847,10 @@ export class TabsTitleControl extends TitleControl {
}
// Open tabs editor
const input = this.group.getEditorByIndex(index);
if (input) {
const editor = this.group.getEditorByIndex(index);
if (editor) {
// Even if focus is preserved make sure to activate the group.
this.group.openEditor(input, { preserveFocus, activation: EditorActivation.ACTIVATE });
this.group.openEditor(editor, { preserveFocus, activation: EditorActivation.ACTIVATE });
}
return undefined;
@@ -859,9 +859,9 @@ export class TabsTitleControl extends TitleControl {
const showContextMenu = (e: Event) => {
EventHelper.stop(e);
const input = this.group.getEditorByIndex(index);
if (input) {
this.onContextMenu(input, e, tab);
const editor = this.group.getEditorByIndex(index);
if (editor) {
this.onContextMenu(editor, e, tab);
}
};
@@ -886,6 +886,11 @@ export class TabsTitleControl extends TitleControl {
if (e.button === 1 /* Middle Button*/) {
EventHelper.stop(e, true /* for https://github.com/microsoft/vscode/issues/56715 */);
const editor = this.group.getEditorByIndex(index);
if (editor && preventEditorClose(this.group, editor, EditorCloseMethod.MOUSE, this.accessor.partOptions)) {
return;
}
this.blockRevealActiveTabOnce();
this.closeEditorAction.run({ groupId: this.group.id, editorIndex: index });
}
@@ -912,9 +917,9 @@ export class TabsTitleControl extends TitleControl {
// Run action on Enter/Space
if (event.equals(KeyCode.Enter) || event.equals(KeyCode.Space)) {
handled = true;
const input = this.group.getEditorByIndex(index);
if (input) {
this.group.openEditor(input);
const editor = this.group.getEditorByIndex(index);
if (editor) {
this.group.openEditor(editor);
}
}
@@ -973,9 +978,9 @@ export class TabsTitleControl extends TitleControl {
disposables.add(addDisposableListener(tab, EventType.CONTEXT_MENU, e => {
EventHelper.stop(e, true);
const input = this.group.getEditorByIndex(index);
if (input) {
this.onContextMenu(input, e, tab);
const editor = this.group.getEditorByIndex(index);
if (editor) {
this.onContextMenu(editor, e, tab);
}
}, true /* use capture to fix https://github.com/microsoft/vscode/issues/19145 */));
@@ -13,7 +13,7 @@ import { ActionsOrientation, prepareActions } from 'vs/base/browser/ui/actionbar
import { ActivePanelContext, PanelFocusContext, getEnabledViewContainerContextKey } from 'vs/workbench/common/contextkeys';
import { CompositePart, ICompositeTitleLabel } from 'vs/workbench/browser/parts/compositePart';
import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
@@ -417,7 +417,7 @@ export abstract class BasePanelPart extends CompositePart<PaneComposite> impleme
disposables.clear();
this.onDidRegisterExtensions();
this.compositeBar.onDidChange(() => this.saveCachedPanels(), this, disposables);
this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e), this, disposables);
this.storageService.onDidChangeValue(StorageScope.PROFILE, this.pinnedPanelsKey, disposables)(() => this.onDidStorageValueChange(), this, disposables);
}));
}
@@ -781,9 +781,8 @@ export abstract class BasePanelPart extends CompositePart<PaneComposite> impleme
return this.toolBar.getItemsWidth() + (this.globalToolBar?.getItemsWidth() ?? 0);
}
private onDidStorageValueChange(e: IStorageValueChangeEvent): void {
if (e.key === this.pinnedPanelsKey && e.scope === StorageScope.PROFILE
&& this.cachedPanelsValue !== this.getStoredCachedPanelsValue() /* This checks if current window changed the value or not */) {
private onDidStorageValueChange(): void {
if (this.cachedPanelsValue !== this.getStoredCachedPanelsValue() /* This checks if current window changed the value or not */) {
this._cachedPanelsValue = undefined;
const newCompositeItems: ICompositeBarItem[] = [];
const compositeItems = this.compositeBar.getCompositeBarItems();
@@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { isStatusbarEntryLocation, IStatusbarEntryPriority, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
import { hide, show, isAncestor } from 'vs/base/browser/dom';
import { IStorageService, StorageScope, IStorageValueChangeEvent, StorageTarget } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { Emitter } from 'vs/base/common/event';
export interface IStatusbarViewModelEntry {
@@ -57,43 +57,41 @@ export class StatusbarViewModel extends Disposable {
}
private registerListeners(): void {
this._register(this.storageService.onDidChangeValue(e => this.onDidStorageValueChange(e)));
this._register(this.storageService.onDidChangeValue(StorageScope.PROFILE, StatusbarViewModel.HIDDEN_ENTRIES_KEY, this._register(new DisposableStore()))(() => this.onDidStorageValueChange()));
}
private onDidStorageValueChange(event: IStorageValueChangeEvent): void {
if (event.key === StatusbarViewModel.HIDDEN_ENTRIES_KEY && event.scope === StorageScope.PROFILE) {
private onDidStorageValueChange(): void {
// Keep current hidden entries
const currentlyHidden = new Set(this.hidden);
// Keep current hidden entries
const currentlyHidden = new Set(this.hidden);
// Load latest state of hidden entries
this.hidden.clear();
this.restoreState();
// Load latest state of hidden entries
this.hidden.clear();
this.restoreState();
const changed = new Set<string>();
const changed = new Set<string>();
// Check for each entry that is now visible
for (const id of currentlyHidden) {
if (!this.hidden.has(id)) {
changed.add(id);
}
// Check for each entry that is now visible
for (const id of currentlyHidden) {
if (!this.hidden.has(id)) {
changed.add(id);
}
}
// Check for each entry that is now hidden
for (const id of this.hidden) {
if (!currentlyHidden.has(id)) {
changed.add(id);
}
// Check for each entry that is now hidden
for (const id of this.hidden) {
if (!currentlyHidden.has(id)) {
changed.add(id);
}
}
// Update visibility for entries have changed
if (changed.size > 0) {
for (const entry of this._entries) {
if (changed.has(entry.id)) {
this.updateVisibility(entry.id, true);
// Update visibility for entries have changed
if (changed.size > 0) {
for (const entry of this._entries) {
if (changed.has(entry.id)) {
this.updateVisibility(entry.id, true);
changed.delete(entry.id);
}
changed.delete(entry.id);
}
}
}
@@ -176,6 +176,18 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
],
'markdownDescription': localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'pinnedTabSizing' }, "Controls the size of pinned editor tabs. Pinned tabs are sorted to the beginning of all opened tabs and typically do not close until unpinned. This value is ignored when `#workbench.editor.showTabs#` is disabled.")
},
'workbench.editor.preventPinnedEditorClose': {
'type': 'string',
'enum': ['keyboardAndMouse', 'keyboard', 'mouse', 'never'],
'default': 'keyboardAndMouse',
'enumDescriptions': [
localize('workbench.editor.preventPinnedEditorClose.always', "Always prevent closing the pinned editor when using mouse middle click or keyboard."),
localize('workbench.editor.preventPinnedEditorClose.onlyKeyboard', "Prevent closing the pinned editor when using the keyboard."),
localize('workbench.editor.preventPinnedEditorClose.onlyMouse', "Prevent closing the pinned editor when using mouse middle click."),
localize('workbench.editor.preventPinnedEditorClose.never', "Never prevent closing a pinned editor.")
],
description: localize('workbench.editor.preventPinnedEditorClose', "Controls whether pinned editors should close when keyboard or middle mouse click is used for closing."),
},
'workbench.editor.splitSizing': {
'type': 'string',
'enum': ['auto', 'distribute', 'split'],
@@ -194,7 +206,7 @@ const registry = Registry.as<IConfigurationRegistry>(ConfigurationExtensions.Con
},
'workbench.editor.focusRecentEditorAfterClose': {
'type': 'boolean',
'description': localize('focusRecentEditorAfterClose', "Controls whether tabs are closed in most recently used order or from left to right."),
'description': localize('focusRecentEditorAfterClose', "Controls whether editors are closed in most recently used order or from left to right."),
'default': true
},
'workbench.editor.showIcons': {
+23
View File
@@ -1098,6 +1098,7 @@ interface IEditorPartConfiguration {
tabSizingFixedMinWidth?: number;
tabSizingFixedMaxWidth?: number;
pinnedTabSizing?: 'normal' | 'compact' | 'shrink';
preventPinnedEditorClose?: PreventPinnedEditorClose;
titleScrollbarSizing?: 'default' | 'large';
focusRecentEditorAfterClose?: boolean;
showIcons?: boolean;
@@ -1340,6 +1341,28 @@ class EditorResourceAccessorImpl {
}
}
export type PreventPinnedEditorClose = 'keyboardAndMouse' | 'keyboard' | 'mouse' | 'never' | undefined;
export enum EditorCloseMethod {
UNKNOWN,
KEYBOARD,
MOUSE
}
export function preventEditorClose(group: IEditorGroup, editor: EditorInput, method: EditorCloseMethod, configuration: IEditorPartConfiguration): boolean {
if (!group.isSticky(editor)) {
return false; // only interested in sticky editors
}
switch (configuration.preventPinnedEditorClose) {
case 'keyboardAndMouse': return method === EditorCloseMethod.MOUSE || method === EditorCloseMethod.KEYBOARD;
case 'mouse': return method === EditorCloseMethod.MOUSE;
case 'keyboard': return method === EditorCloseMethod.KEYBOARD;
}
return false;
}
export const EditorResourceAccessor = new EditorResourceAccessorImpl();
export const enum CloseDirection {
@@ -26,10 +26,10 @@ import { getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/
import { CodeActionController } from 'vs/editor/contrib/codeAction/browser/codeActionController';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { AccessibilityVerbositySettingId, AccessibleViewAction, AccessibleViewNextAction, AccessibleViewPreviousAction } from 'vs/workbench/contrib/accessibility/browser/accessibilityContribution';
import { ILayoutService } from 'vs/platform/layout/browser/layoutService';
const enum DEFAULT {
WIDTH = 800,
TOP = 3
const enum DIMENSIONS {
MAX_WIDTH = 600
}
export interface IAccessibleContentProvider {
@@ -89,7 +89,8 @@ class AccessibleView extends Disposable {
@IContextViewService private readonly _contextViewService: IContextViewService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IAccessibilityService private readonly _accessibilityService: IAccessibilityService,
@IKeybindingService private readonly _keybindingService: IKeybindingService
@IKeybindingService private readonly _keybindingService: IKeybindingService,
@ILayoutService private readonly _layoutService: ILayoutService
) {
super();
this._accessiblityHelpIsShown = accessibilityHelpIsShown.bindTo(this._contextKeyService);
@@ -128,7 +129,7 @@ class AccessibleView extends Disposable {
show(provider: IAccessibleContentProvider): void {
const delegate: IContextViewDelegate = {
getAnchor: () => { return { x: (window.innerWidth / 2) - (DEFAULT.WIDTH / 2), y: DEFAULT.TOP }; },
getAnchor: () => { return { x: (window.innerWidth / 2) - ((Math.min(this._layoutService.dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH)) / 2), y: this._layoutService.offset.quickPickTop }; },
render: (container) => {
container.classList.add('accessible-view-container');
return this._render(provider, container);
@@ -228,11 +229,16 @@ class AccessibleView extends Disposable {
}));
disposableStore.add(this._editorWidget.onDidBlurEditorText(() => this._contextViewService.hideContextView()));
disposableStore.add(this._editorWidget.onDidContentSizeChange(() => this._layout()));
disposableStore.add(this._layoutService.onDidLayout(() => this._layout()));
return disposableStore;
}
private _layout(): void {
this._editorWidget.layout({ width: DEFAULT.WIDTH, height: this._editorWidget.getContentHeight() });
const dimension = this._layoutService.dimension;
const maxHeight = dimension.height && dimension.height * .4;
const height = Math.min(maxHeight, this._editorWidget.getContentHeight());
const width = Math.min(dimension.width * 0.62 /* golden cut */, DIMENSIONS.MAX_WIDTH);
this._editorWidget.layout({ width, height });
}
private async _getTextModel(resource: URI): Promise<ITextModel | null> {
@@ -9,4 +9,7 @@
color: var(--vscode-editorWidget-foreground);
box-shadow: 0 2px 8px var(--vscode-widget-shadow);
border: 2px solid var(--vscode-focusBorder);
border-radius: 6px;
margin-top: -1px;
z-index: 2550;
}
@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { localize } from 'vs/nls';
import { Action2, MenuId, MenuRegistry, registerAction2 } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
@@ -11,7 +11,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'
import { IFileService } from 'vs/platform/files/common/files';
import { IProductService } from 'vs/platform/product/common/productService';
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { createSyncHeaders, IAuthenticationProvider, IResourceRefHandle } from 'vs/platform/userDataSync/common/userDataSync';
import { AuthenticationSession, AuthenticationSessionsChangeEvent, IAuthenticationService } from 'vs/workbench/services/authentication/common/authentication';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@@ -91,7 +91,7 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
this._register(this.authenticationService.onDidChangeSessions((e) => this.onDidChangeSessions(e.event)));
// If another window changes the preferred session storage, reset our cached auth state in memory
this._register(this.storageService.onDidChangeValue(e => this.onDidChangeStorage(e)));
this._register(this.storageService.onDidChangeValue(StorageScope.APPLICATION, EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY, this._register(new DisposableStore()))(() => this.onDidChangeStorage()));
this.registerSignInAction();
this.registerResetAuthenticationAction();
@@ -431,18 +431,14 @@ export class EditSessionsWorkbenchService extends Disposable implements IEditSes
return accounts.find((account) => account.session.id === this.existingSessionId);
}
private async onDidChangeStorage(e: IStorageValueChangeEvent): Promise<void> {
if (e.key === EditSessionsWorkbenchService.CACHED_SESSION_STORAGE_KEY
&& e.scope === StorageScope.APPLICATION
) {
const newSessionId = this.existingSessionId;
const previousSessionId = this.authenticationInfo?.sessionId;
private async onDidChangeStorage(): Promise<void> {
const newSessionId = this.existingSessionId;
const previousSessionId = this.authenticationInfo?.sessionId;
if (previousSessionId !== newSessionId) {
this.logService.trace(`Resetting authentication state because authentication session ID preference changed from ${previousSessionId} to ${newSessionId}.`);
this.authenticationInfo = undefined;
this.initialized = false;
}
if (previousSessionId !== newSessionId) {
this.logService.trace(`Resetting authentication state because authentication session ID preference changed from ${previousSessionId} to ${newSessionId}.`);
this.authenticationInfo = undefined;
this.initialized = false;
}
}
@@ -1,11 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Registry } from 'vs/platform/registry/common/platform';
import { FeedbackStatusbarConribution } from 'vs/workbench/contrib/feedback/browser/feedbackStatusbarItem';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/workbench/services/lifecycle/common/lifecycle';
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(FeedbackStatusbarConribution, LifecyclePhase.Starting);
@@ -1,455 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/feedback';
import { localize } from 'vs/nls';
import { IDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle';
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
import { ICommandService } from 'vs/platform/commands/common/commands';
import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { editorWidgetBackground, editorWidgetForeground, widgetShadow, inputBorder, inputForeground, inputBackground, editorBackground, asCssVariable, asCssVariableWithDefault, widgetBorder, contrastBorder } from 'vs/platform/theme/common/colorRegistry';
import { append, $, addDisposableListener, EventType, EventHelper, prepend } from 'vs/base/browser/dom';
import { IAnchor } from 'vs/base/browser/ui/contextview/contextview';
import { Button } from 'vs/base/browser/ui/button/button';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification } from 'vs/base/common/actions';
import { IStatusbarService } from 'vs/workbench/services/statusbar/browser/statusbar';
import { IProductService } from 'vs/platform/product/common/productService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
import { KeyCode } from 'vs/base/common/keyCodes';
import { Codicon } from 'vs/base/common/codicons';
import { ThemeIcon } from 'vs/base/common/themables';
import { Emitter } from 'vs/base/common/event';
import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService';
import { defaultButtonStyles } from 'vs/platform/theme/browser/defaultStyles';
export interface IFeedback {
feedback: string;
sentiment: number;
}
export interface IFeedbackDelegate {
submitFeedback(feedback: IFeedback, openerService: IOpenerService): void;
getCharacterLimit(sentiment: number): number;
}
export interface IFeedbackWidgetOptions {
feedbackService: IFeedbackDelegate;
}
export class FeedbackWidget extends Disposable {
private visible: boolean | undefined;
private _onDidChangeVisibility = new Emitter<boolean>();
readonly onDidChangeVisibility = this._onDidChangeVisibility.event;
private maxFeedbackCharacters: number;
private feedback: string = '';
private sentiment: number = 1;
private readonly feedbackDelegate: IFeedbackDelegate;
private feedbackForm: HTMLFormElement | undefined = undefined;
private feedbackDescriptionInput: HTMLTextAreaElement | undefined = undefined;
private smileyInput: HTMLElement | undefined = undefined;
private frownyInput: HTMLElement | undefined = undefined;
private sendButton: Button | undefined = undefined;
private hideButton: HTMLInputElement | undefined = undefined;
private remainingCharacterCount: HTMLElement | undefined = undefined;
private requestFeatureLink: string | undefined;
private isPure: boolean = true;
constructor(
options: IFeedbackWidgetOptions,
@IContextViewService private readonly contextViewService: IContextViewService,
@IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService,
@ICommandService private readonly commandService: ICommandService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IIntegrityService private readonly integrityService: IIntegrityService,
@IThemeService private readonly themeService: IThemeService,
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IProductService productService: IProductService,
@IOpenerService private readonly openerService: IOpenerService
) {
super();
this.feedbackDelegate = options.feedbackService;
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
if (productService.sendASmile) {
this.requestFeatureLink = productService.sendASmile.requestFeatureUrl;
}
this.integrityService.isPure().then(result => {
if (!result.isPure) {
this.isPure = false;
}
});
// Hide feedback widget whenever notifications appear
this._register(this.layoutService.onDidChangeNotificationsVisibility(visible => {
if (visible) {
this.hide();
}
}));
}
private getAnchor(): IAnchor {
const dimension = this.layoutService.dimension;
return {
x: dimension.width - 8,
y: dimension.height - 31
};
}
private renderContents(container: HTMLElement): IDisposable {
const disposables = new DisposableStore();
container.classList.add('monaco-menu-container');
// Form
this.feedbackForm = append<HTMLFormElement>(container, $('form.feedback-form'));
this.feedbackForm.setAttribute('action', 'javascript:void(0);');
// Title
append(this.feedbackForm, $('h2.title')).textContent = localize("label.sendASmile", "Tweet us your feedback.");
// Close Button (top right)
const closeBtn = append(this.feedbackForm, $(`div.cancel${ThemeIcon.asCSSSelector(Codicon.close)}`));
closeBtn.tabIndex = 0;
closeBtn.setAttribute('role', 'button');
closeBtn.title = localize('close', "Close");
disposables.add(addDisposableListener(container, EventType.KEY_DOWN, keyboardEvent => {
const standardKeyboardEvent = new StandardKeyboardEvent(keyboardEvent);
if (standardKeyboardEvent.keyCode === KeyCode.Escape) {
this.hide();
}
}));
disposables.add(addDisposableListener(closeBtn, EventType.MOUSE_OVER, () => {
const theme = this.themeService.getColorTheme();
let darkenFactor: number | undefined;
switch (theme.type) {
case 'light':
darkenFactor = 0.1;
break;
case 'dark':
darkenFactor = 0.2;
break;
}
if (darkenFactor) {
const backgroundBaseColor = theme.getColor(editorWidgetBackground);
if (backgroundBaseColor) {
const backgroundColor = backgroundBaseColor.darken(darkenFactor);
if (backgroundColor) {
closeBtn.style.backgroundColor = backgroundColor.toString();
}
}
}
}));
disposables.add(addDisposableListener(closeBtn, EventType.MOUSE_OUT, () => {
closeBtn.style.backgroundColor = '';
}));
this.invoke(closeBtn, disposables, () => this.hide());
// Content
const content = append(this.feedbackForm, $('div.content'));
// Sentiment Buttons
const sentimentContainer = append(content, $('div'));
if (!this.isPure) {
append(sentimentContainer, $('span')).textContent = localize("patchedVersion1", "Your installation is corrupt.");
sentimentContainer.appendChild(document.createElement('br'));
append(sentimentContainer, $('span')).textContent = localize("patchedVersion2", "Please specify this if you submit a bug.");
sentimentContainer.appendChild(document.createElement('br'));
}
append(sentimentContainer, $('span')).textContent = localize("sentiment", "How was your experience?");
const feedbackSentiment = append(sentimentContainer, $('div.feedback-sentiment'));
// Sentiment: Smiley
this.smileyInput = append(feedbackSentiment, $('div.sentiment'));
this.smileyInput.classList.add('smile');
this.smileyInput.setAttribute('aria-checked', 'false');
this.smileyInput.setAttribute('aria-label', localize('smileCaption', "Happy Feedback Sentiment"));
this.smileyInput.setAttribute('role', 'checkbox');
this.smileyInput.title = localize('smileCaption', "Happy Feedback Sentiment");
this.smileyInput.tabIndex = 0;
this.invoke(this.smileyInput, disposables, () => this.setSentiment(true));
// Sentiment: Frowny
this.frownyInput = append(feedbackSentiment, $('div.sentiment'));
this.frownyInput.classList.add('frown');
this.frownyInput.setAttribute('aria-checked', 'false');
this.frownyInput.setAttribute('aria-label', localize('frownCaption', "Sad Feedback Sentiment"));
this.frownyInput.setAttribute('role', 'checkbox');
this.frownyInput.title = localize('frownCaption', "Sad Feedback Sentiment");
this.frownyInput.tabIndex = 0;
this.invoke(this.frownyInput, disposables, () => this.setSentiment(false));
if (this.sentiment === 1) {
this.smileyInput.classList.add('checked');
this.smileyInput.setAttribute('aria-checked', 'true');
} else {
this.frownyInput.classList.add('checked');
this.frownyInput.setAttribute('aria-checked', 'true');
}
// Contact Us Box
const contactUsContainer = append(content, $('div.contactus'));
append(contactUsContainer, $('span')).textContent = localize("other ways to contact us", "Other ways to contact us");
const channelsContainer = append(contactUsContainer, $('div.channels'));
// Contact: Submit a Bug
const submitBugLinkContainer = append(channelsContainer, $('div'));
const submitBugLink = append(submitBugLinkContainer, $('a'));
submitBugLink.setAttribute('target', '_blank');
submitBugLink.setAttribute('href', '#');
submitBugLink.textContent = localize("submit a bug", "Submit a bug");
submitBugLink.tabIndex = 0;
disposables.add(addDisposableListener(submitBugLink, 'click', e => {
EventHelper.stop(e);
const actionId = 'workbench.action.openIssueReporter';
this.commandService.executeCommand(actionId);
this.hide();
this.telemetryService.publicLog2<WorkbenchActionExecutedEvent, WorkbenchActionExecutedClassification>('workbenchActionExecuted', { id: actionId, from: 'feedback' });
}));
// Contact: Request a Feature
if (!!this.requestFeatureLink) {
const requestFeatureLinkContainer = append(channelsContainer, $('div'));
const requestFeatureLink = append(requestFeatureLinkContainer, $('a'));
requestFeatureLink.setAttribute('target', '_blank');
requestFeatureLink.setAttribute('href', this.requestFeatureLink);
requestFeatureLink.textContent = localize("request a missing feature", "Request a missing feature");
requestFeatureLink.tabIndex = 0;
disposables.add(addDisposableListener(requestFeatureLink, 'click', e => this.hide()));
}
// Remaining Characters
const remainingCharacterCountContainer = append(this.feedbackForm, $('h3'));
remainingCharacterCountContainer.textContent = localize("tell us why", "Tell us why?");
this.remainingCharacterCount = append(remainingCharacterCountContainer, $('span.char-counter'));
this.remainingCharacterCount.textContent = this.getCharCountText(0);
// Feedback Input Form
this.feedbackDescriptionInput = append<HTMLTextAreaElement>(this.feedbackForm, $('textarea.feedback-description'));
this.feedbackDescriptionInput.rows = 3;
this.feedbackDescriptionInput.maxLength = this.maxFeedbackCharacters;
this.feedbackDescriptionInput.textContent = this.feedback;
this.feedbackDescriptionInput.required = true;
this.feedbackDescriptionInput.setAttribute('aria-label', localize("feedbackTextInput", "Tell us your feedback"));
this.feedbackDescriptionInput.focus();
disposables.add(addDisposableListener(this.feedbackDescriptionInput, 'keyup', () => this.updateCharCountText()));
// Feedback Input Form Buttons Container
const buttonsContainer = append(this.feedbackForm, $('div.form-buttons'));
// Checkbox: Hide Feedback Smiley
const hideButtonContainer = append(buttonsContainer, $('div.hide-button-container'));
this.hideButton = append(hideButtonContainer, $('input.hide-button')) as HTMLInputElement;
this.hideButton.type = 'checkbox';
this.hideButton.checked = true;
this.hideButton.id = 'hide-button';
const hideButtonLabel = append(hideButtonContainer, $('label'));
hideButtonLabel.setAttribute('for', 'hide-button');
hideButtonLabel.textContent = localize('showFeedback', "Show Feedback Icon in Status Bar");
// Button: Send Feedback
this.sendButton = new Button(buttonsContainer, defaultButtonStyles);
this.sendButton.enabled = false;
this.sendButton.label = localize('tweet', "Tweet");
prepend(this.sendButton.element, $(`span${ThemeIcon.asCSSSelector(Codicon.twitter)}`));
this.sendButton.element.classList.add('send');
this.sendButton.element.title = localize('tweetFeedback', "Tweet Feedback");
this.sendButton.onDidClick(() => this.onSubmit());
if (this.feedbackForm) {
this.feedbackForm.style.backgroundColor = asCssVariable(editorWidgetBackground);
this.feedbackForm.style.color = asCssVariable(editorWidgetForeground);
this.feedbackForm.style.boxShadow = `0 0 8px 2px ${asCssVariable(widgetShadow)}`;
this.feedbackForm.style.border = `1px solid ${asCssVariable(widgetBorder)}`;
}
if (this.feedbackDescriptionInput) {
this.feedbackDescriptionInput.style.backgroundColor = asCssVariable(inputBackground);
this.feedbackDescriptionInput.style.color = asCssVariable(inputForeground);
this.feedbackDescriptionInput.style.border = `1px solid ${asCssVariableWithDefault(inputBorder, 'transparent')}`;
}
contactUsContainer.style.backgroundColor = asCssVariable(editorBackground);
contactUsContainer.style.border = `1px solid ${asCssVariableWithDefault(contrastBorder, 'transparent')}`;
return {
dispose: () => {
this.feedbackForm = undefined;
this.feedbackDescriptionInput = undefined;
this.smileyInput = undefined;
this.frownyInput = undefined;
disposables.dispose();
}
};
}
private updateFeedbackDescription() {
if (this.feedbackDescriptionInput && this.feedbackDescriptionInput.textLength > this.maxFeedbackCharacters) {
this.feedbackDescriptionInput.value = this.feedbackDescriptionInput.value.substring(0, this.maxFeedbackCharacters);
}
}
private getCharCountText(charCount: number): string {
const remaining = this.maxFeedbackCharacters - charCount;
const text = (remaining === 1)
? localize("character left", "character left")
: localize("characters left", "characters left");
return `(${remaining} ${text})`;
}
private updateCharCountText(): void {
if (this.feedbackDescriptionInput && this.remainingCharacterCount && this.sendButton) {
this.remainingCharacterCount.innerText = this.getCharCountText(this.feedbackDescriptionInput.value.length);
this.sendButton.enabled = this.feedbackDescriptionInput.value.length > 0;
}
}
private setSentiment(smile: boolean): void {
if (smile) {
if (this.smileyInput) {
this.smileyInput.classList.add('checked');
this.smileyInput.setAttribute('aria-checked', 'true');
}
if (this.frownyInput) {
this.frownyInput.classList.remove('checked');
this.frownyInput.setAttribute('aria-checked', 'false');
}
} else {
if (this.frownyInput) {
this.frownyInput.classList.add('checked');
this.frownyInput.setAttribute('aria-checked', 'true');
}
if (this.smileyInput) {
this.smileyInput.classList.remove('checked');
this.smileyInput.setAttribute('aria-checked', 'false');
}
}
this.sentiment = smile ? 1 : 0;
this.maxFeedbackCharacters = this.feedbackDelegate.getCharacterLimit(this.sentiment);
this.updateFeedbackDescription();
this.updateCharCountText();
if (this.feedbackDescriptionInput) {
this.feedbackDescriptionInput.maxLength = this.maxFeedbackCharacters;
}
}
private invoke(element: HTMLElement, disposables: DisposableStore, callback: () => void): HTMLElement {
disposables.add(addDisposableListener(element, 'click', callback));
disposables.add(addDisposableListener(element, 'keypress', e => {
if (e instanceof KeyboardEvent) {
const keyboardEvent = <KeyboardEvent>e;
if (keyboardEvent.keyCode === 13 || keyboardEvent.keyCode === 32) { // Enter or Spacebar
callback();
}
}
}));
return element;
}
show(): void {
if (this.visible) {
return;
}
this.visible = true;
this.contextViewService.showContextView({
getAnchor: () => this.getAnchor(),
render: (container) => {
return this.renderContents(container);
},
onDOMEvent: (e, activeElement) => {
this.onEvent(e, activeElement);
},
onHide: () => this._onDidChangeVisibility.fire(false)
});
this._onDidChangeVisibility.fire(true);
this.updateCharCountText();
}
hide(): void {
if (!this.visible) {
return;
}
if (this.feedbackDescriptionInput) {
this.feedback = this.feedbackDescriptionInput.value;
}
if (this.hideButton && !this.hideButton.checked) {
this.statusbarService.updateEntryVisibility('status.feedback', false);
}
this.visible = false;
this.contextViewService.hideContextView();
}
isVisible(): boolean {
return !!this.visible;
}
private onEvent(e: Event, activeElement: HTMLElement): void {
if (e instanceof KeyboardEvent) {
const keyboardEvent = <KeyboardEvent>e;
if (keyboardEvent.keyCode === 27) { // Escape
this.hide();
}
}
}
private onSubmit(): void {
if (!this.feedbackForm || !this.feedbackDescriptionInput || (this.feedbackForm.checkValidity && !this.feedbackForm.checkValidity())) {
return;
}
this.feedbackDelegate.submitFeedback({
feedback: this.feedbackDescriptionInput.value,
sentiment: this.sentiment
}, this.openerService);
this.hide();
}
}
@@ -1,118 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Disposable } from 'vs/base/common/lifecycle';
import { FeedbackWidget, IFeedback, IFeedbackDelegate } from 'vs/workbench/contrib/feedback/browser/feedback';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IProductService } from 'vs/platform/product/common/productService';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IStatusbarService, StatusbarAlignment, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/workbench/services/statusbar/browser/statusbar';
import { localize } from 'vs/nls';
import { CommandsRegistry, ICommandService } from 'vs/platform/commands/common/commands';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { URI } from 'vs/base/common/uri';
import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions';
import { Categories } from 'vs/platform/action/common/actionCommonCategories';
import { HIDE_NOTIFICATIONS_CENTER, HIDE_NOTIFICATION_TOAST } from 'vs/workbench/browser/parts/notifications/notificationsCommands';
import { isIOS } from 'vs/base/common/platform';
class TwitterFeedbackService implements IFeedbackDelegate {
private static TWITTER_URL: string = 'https://twitter.com/intent/tweet';
private static VIA_NAME: string = 'code';
private static HASHTAGS: string[] = ['HappyCoding'];
private combineHashTagsAsString(): string {
return TwitterFeedbackService.HASHTAGS.join(',');
}
submitFeedback(feedback: IFeedback, openerService: IOpenerService): void {
const queryString = `?${feedback.sentiment === 1 ? `hashtags=${this.combineHashTagsAsString()}&` : ''}ref_src=twsrc%5Etfw&related=twitterapi%2Ctwitter&text=${encodeURIComponent(feedback.feedback)}&tw_p=tweetbutton&via=${TwitterFeedbackService.VIA_NAME}`;
const url = TwitterFeedbackService.TWITTER_URL + queryString;
openerService.open(URI.parse(url));
}
getCharacterLimit(sentiment: number): number {
let length: number = 0;
if (sentiment === 1) {
TwitterFeedbackService.HASHTAGS.forEach(element => {
length += element.length + 2;
});
}
if (TwitterFeedbackService.VIA_NAME) {
length += ` via @${TwitterFeedbackService.VIA_NAME}`.length;
}
return 280 - length;
}
}
export class FeedbackStatusbarConribution extends Disposable implements IWorkbenchContribution {
private static readonly TOGGLE_FEEDBACK_COMMAND = 'help.tweetFeedback';
private widget: FeedbackWidget | undefined;
private entry: IStatusbarEntryAccessor | undefined;
constructor(
@IStatusbarService private readonly statusbarService: IStatusbarService,
@IProductService productService: IProductService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@ICommandService private readonly commandService: ICommandService) {
super();
if (productService.sendASmile && !isIOS) {
this.createFeedbackStatusEntry();
}
}
private createFeedbackStatusEntry(): void {
// Status entry
this.entry = this._register(this.statusbarService.addEntry(this.getStatusEntry(), 'status.feedback', StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */));
// Command to toggle
CommandsRegistry.registerCommand(FeedbackStatusbarConribution.TOGGLE_FEEDBACK_COMMAND, () => this.toggleFeedback());
MenuRegistry.appendMenuItem(MenuId.CommandPalette, {
command: {
id: FeedbackStatusbarConribution.TOGGLE_FEEDBACK_COMMAND,
category: Categories.Help,
title: localize('status.feedback', "Tweet Feedback")
}
});
}
private toggleFeedback(): void {
if (!this.widget) {
this.widget = this._register(this.instantiationService.createInstance(FeedbackWidget, {
feedbackService: this.instantiationService.createInstance(TwitterFeedbackService)
}));
this._register(this.widget.onDidChangeVisibility(visible => this.entry!.update(this.getStatusEntry(visible))));
}
if (this.widget) {
if (!this.widget.isVisible()) {
this.commandService.executeCommand(HIDE_NOTIFICATION_TOAST);
this.commandService.executeCommand(HIDE_NOTIFICATIONS_CENTER);
this.widget.show();
} else {
this.widget.hide();
}
}
}
private getStatusEntry(showBeak?: boolean): IStatusbarEntry {
return {
name: localize('status.feedback.name', "Feedback"),
text: '$(feedback)',
ariaLabel: localize('status.feedback', "Tweet Feedback"),
tooltip: localize('status.feedback', "Tweet Feedback"),
command: FeedbackStatusbarConribution.TOGGLE_FEEDBACK_COMMAND,
showBeak
};
}
}
@@ -1,245 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-workbench .feedback-form {
width: 420px;
top: 30px;
right: 6px;
padding: 1em;
cursor: default;
border-radius: 4px;
}
.monaco-workbench .feedback-form h2 {
margin: 0;
padding: 0;
font-weight: normal;
font-size: 1.8em;
}
.monaco-workbench .feedback-form h3 {
margin: 1em 0 0;
padding: 0;
font-weight: normal;
font-size: 1.2em;
}
.monaco-workbench .feedback-form .content {
font-size: 1.2em;
}
.monaco-workbench .feedback-form .content > div {
display: inline-block;
vertical-align: top;
margin-top: 20px;
}
.monaco-workbench .feedback-form .content .contactus {
padding: 10px;
float: right;
}
.monaco-workbench .feedback-form .content .channels {
margin-top: 5px;
font-size: 0.9em;
}
.monaco-workbench .char-counter {
padding-left: 3px;
}
.monaco-workbench .feedback-form .content .channels a {
padding: 2px 0;
color: var(--vscode-textLink-foreground, var(--vscode-contrastBorder));
}
.monaco-workbench .feedback-form .content .channels a:hover {
text-decoration: underline;
}
.monaco-workbench .feedback-form .feedback-alias, .monaco-workbench .feedback-form .feedback-description {
resize: none;
font-size: 1.1em;
margin: 6px 0 0;
width: 100%;
padding: 3px 2px;
box-sizing: border-box;
}
.monaco-workbench .feedback-form .feedback-empty {
margin-top: .2em;
}
.monaco-workbench .feedback-form .feedback-alias-checkbox {
display: inline-block;
vertical-align: text-top;
margin-left: 0;
}
.monaco-workbench .feedback-form .feedback-alias {
height: 26px;
}
.monaco-workbench .feedback-form .feedback-alias:disabled {
opacity: 0.6;
}
.monaco-workbench .feedback-form .cancel {
position: absolute;
top: 0;
right: 0;
padding: .5em;
width: 22px;
height: 22px;
line-height: 22px;
border: none;
cursor: pointer;
}
.monaco-workbench .feedback-form .form-buttons {
margin-top: 18px;
text-align: right;
}
.monaco-workbench .feedback-form .sentiment {
height: 32px;
width: 32px;
display: inline-block;
margin: .5em 0;
cursor: pointer;
box-sizing: border-box;
}
.monaco-workbench .feedback-form .sentiment:hover {
background-color: #eaeaea;
}
.monaco-workbench .feedback-form .sentiment.checked {
border: 1px solid var(--vscode-inputOption-activeBorder);
}
/* Theming */
.monaco-workbench.vs .feedback-form .feedback-alias,
.monaco-workbench.vs .feedback-form .feedback-description {
font-family: inherit;
border: 1px solid transparent;
}
.monaco-workbench .feedback-form .form-buttons {
display: flex;
}
.monaco-workbench .feedback-form .form-buttons .hide-button-container {
display: flex;
}
.monaco-workbench .feedback-form .form-buttons .hide-button-container input,
.monaco-workbench .feedback-form .form-buttons .hide-button-container label {
align-self: center;
}
.monaco-workbench .feedback-form .form-buttons .send {
width: auto;
padding: 8px 12px;
margin-left: auto;
display: flex;
align-items: center;
}
.monaco-workbench .feedback-form .form-buttons .send .codicon {
color: currentColor;
font-size: 20px;
padding-right: 8px;
}
.monaco-workbench .feedback-form .form-buttons .send.in-progress,
.monaco-workbench .feedback-form .form-buttons .send:hover {
background-color: #006BB3;
}
.monaco-workbench .feedback-form .form-buttons .send:disabled {
pointer-events: none;
cursor: not-allowed;
opacity: .65;
}
.monaco-workbench .feedback-form .form-buttons .send.success {
background-color: #2d883e;
}
.monaco-workbench .feedback-form .form-buttons .send.error {
background-color: #E51400;
}
.monaco-workbench.vs-dark .feedback-form h3 {
font-weight: normal;
font-size: 1.2em;
}
.monaco-workbench.vs-dark .feedback-form .sentiment:hover {
background-color: rgba(30,30,30,0.8);
}
.monaco-workbench.vs-dark .feedback-form .feedback-alias,
.monaco-workbench.vs-dark .feedback-form .feedback-description {
font-family: inherit;
}
.monaco-workbench .feedback-form .sentiment.smile {
background-image: url('happy.svg');
background-position: center;
background-repeat: no-repeat;
}
.monaco-workbench .feedback-form .sentiment.frown {
background-image: url('sad.svg');
background-position: center;
background-repeat: no-repeat;
}
/* High Contrast Theming */
.monaco-workbench.hc-black .feedback-form {
outline: 2px solid #6fc3df;
outline-offset: -2px;
}
.monaco-workbench.hc-light .feedback-form {
outline: 2px solid #0F4A85;
outline-offset: -2px;
}
.monaco-workbench.hc-black .feedback-form .feedback-alias,
.monaco-workbench.hc-black .feedback-form .feedback-description,
.monaco-workbench.hc-light .feedback-form .feedback-alias,
.monaco-workbench.hc-light .feedback-form .feedback-description {
font-family: inherit;
}
.monaco-workbench.hc-black .feedback-form .content .contactus,
.monaco-workbench.hc-light .feedback-form .content .contactus {
padding: 10px;
float: right;
}
.monaco-workbench.hc-black .feedback-form .form-buttons .send,
.monaco-workbench.hc-black .feedback-form .form-buttons .send.in-progress,
.monaco-workbench.hc-black .feedback-form .form-buttons .send.success {
background-color: #0C141F;
color: #D4D4D4;
border: 1px solid #6FC3DF;
}
.monaco-workbench.hc-light .feedback-form .form-buttons .send,
.monaco-workbench.hc-light .feedback-form .form-buttons .send.in-progress,
.monaco-workbench.hc-light .feedback-form .form-buttons .send.success {
background-color: #FFFFFF;
color: #292929;
border: 1px solid #0F4A85;
}
.monaco-workbench.hc-black .feedback-form .form-buttons .send:hover {
background-color: #0C141F;
}
@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16" enable-background="new 0 0 16 16"><g><path fill="#fc0" d="M8 1c-3.866 0-7 3.134-7 7s3.134 7 7 7 7-3.134 7-7-3.134-7-7-7z"/><path fill="#424242" d="M11 6.5c0 .5-.447.5-1 .5s-1 0-1-.5c0-1.104 1-1.5 1-1.5s1 .396 1 1.5z"/><path fill="#424242" d="M10.943 9.025c-.457 1.177-1.644 2.058-2.943 2.058s-2.455-.881-2.899-2.058h-.952c.455 1.709 1.999 2.975 3.851 2.975 1.853 0 3.396-1.266 3.851-2.975h-.908z"/><path fill="#424242" d="M7 6.5s-.447.5-1 .5-1 0-1-.5c0-1.104 1-1.5 1-1.5s1 .396 1 1.5z"/></g></svg>

Before

Width:  |  Height:  |  Size: 580 B

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 16 16" enable-background="new 0 0 16 16"><g><circle fill="#fc0" cx="8" cy="8" r="7"/><path fill="#424242" d="M10.973 6.5c0 .5-.447.5-1 .5s-1 0-1-.5c0-1.104 1-1.5 1-1.5s1 .396 1 1.5z"/><path fill="#424242" d="M6.973 6.5c0 .5-.447.5-1 .5s-1 0-1-.5c0-1.104 1-1.5 1-1.5s1 .396 1 1.5z"/><path fill="#424242" d="M5.104 12c.459-1.146 1.593-2 2.869-2 1.277 0 2.439.854 2.912 2h.916c-.475-1.678-1.998-2.917-3.828-2.917s-3.355 1.239-3.83 2.917h.961z"/></g></svg>

Before

Width:  |  Height:  |  Size: 528 B

@@ -13,7 +13,7 @@ import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiati
import { IEditorGroupsService, IEditorGroup, GroupsOrder, GroupOrientation } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { Verbosity, EditorResourceAccessor, SideBySideEditor, IEditorIdentifier, GroupModelChangeKind } from 'vs/workbench/common/editor';
import { Verbosity, EditorResourceAccessor, SideBySideEditor, IEditorIdentifier, GroupModelChangeKind, preventEditorClose, EditorCloseMethod } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SaveAllInGroupAction, CloseGroupAction } from 'vs/workbench/contrib/files/browser/fileActions';
import { OpenEditorsFocusedContext, ExplorerFocusedContext, IFilesConfiguration, OpenEditor } from 'vs/workbench/contrib/files/common/files';
@@ -268,6 +268,10 @@ export class OpenEditorsView extends ViewPane {
// Open when selecting via keyboard
this._register(this.list.onMouseMiddleClick(e => {
if (e && e.element instanceof OpenEditor) {
if (preventEditorClose(e.element.group, e.element.editor, EditorCloseMethod.MOUSE, this.editorGroupService.partOptions)) {
return;
}
e.element.group.closeEditor(e.element.editor, { preserveFocus: true });
}
}));
@@ -26,7 +26,7 @@ import { MarkdownString } from 'vs/base/common/htmlContent';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { Codicon } from 'vs/base/common/codicons';
import { IStorageService, IStorageValueChangeEvent, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { equals } from 'vs/base/common/arrays';
import { URI } from 'vs/base/common/uri';
import { Action2, registerAction2 } from 'vs/platform/actions/common/actions';
@@ -83,7 +83,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
@IOpenerService private readonly _openerService: IOpenerService,
@IStorageService private readonly _storageService: IStorageService,
) {
_storageService.onDidChangeValue(this._handleStorageChange, this, this._disposables);
_storageService.onDidChangeValue(StorageScope.PROFILE, EditorStatusContribution._keyDedicatedItems, this._disposables)(this._handleStorageChange, this, this._disposables);
this._restoreState();
this._interactionCounter = new StoredCounter(_storageService, 'languageStatus.interactCount');
@@ -110,10 +110,7 @@ class EditorStatusContribution implements IWorkbenchContribution {
// --- persisting dedicated items
private _handleStorageChange(e: IStorageValueChangeEvent) {
if (e.key !== EditorStatusContribution._keyDedicatedItems) {
return;
}
private _handleStorageChange() {
this._restoreState();
this._update();
}
@@ -2527,7 +2527,7 @@ class ApplySettingToAllProfilesAction extends Action {
const newValue = distinct(value);
if (this.checked) {
await this.configService.updateValue(this.setting.key, this.configService.inspect(this.setting.key).userLocal?.value, ConfigurationTarget.USER_LOCAL);
await this.configService.updateValue(this.setting.key, this.configService.inspect(this.setting.key).application?.value, ConfigurationTarget.USER_LOCAL);
await this.configService.updateValue(APPLY_ALL_PROFILES_SETTING, newValue.length ? newValue : undefined, ConfigurationTarget.USER_LOCAL);
} else {
await this.configService.updateValue(APPLY_ALL_PROFILES_SETTING, newValue.length ? newValue : undefined, ConfigurationTarget.USER_LOCAL);
@@ -214,15 +214,13 @@ export class RemoteTunnelWorkbenchContribution extends Disposable implements IWo
return true;
};
if (await shouldRecommend()) {
const storageListener = this.storageService.onDidChangeValue(async e => {
if (e.key === REMOTE_TUNNEL_USED_STORAGE_KEY) {
const success = await recommed();
if (success) {
storageListener.dispose();
}
const disposables = this._register(new DisposableStore());
disposables.add(this.storageService.onDidChangeValue(StorageScope.APPLICATION, REMOTE_TUNNEL_USED_STORAGE_KEY, disposables)(async () => {
const success = await recommed();
if (success) {
disposables.dispose();
}
});
}));
}
}
@@ -1237,16 +1237,16 @@ class ViewModel {
this.disposables.add(this.tree.onDidChangeCollapseState(() => this._treeViewStateIsStale = true));
this.storageService.onWillSaveState(e => {
this.disposables.add(this.storageService.onWillSaveState(e => {
if (e.reason === WillSaveStateReason.SHUTDOWN) {
this.storageService.store(`scm.viewState`, JSON.stringify(this.treeViewState), StorageScope.WORKSPACE, StorageTarget.MACHINE);
}
this.mode = this.getViewModelMode();
this.sortKey = this.getViewModelSortKey();
});
}));
this.storageService.onDidChangeValue(e => {
this.disposables.add(this.storageService.onDidChangeValue(StorageScope.WORKSPACE, undefined, this.disposables)(e => {
switch (e.key) {
case 'scm.viewMode':
this.mode = this.getViewModelMode();
@@ -1255,7 +1255,7 @@ class ViewModel {
this.sortKey = this.getViewModelSortKey();
break;
}
});
}));
}
private onDidChangeConfiguration(e?: IConfigurationChangeEvent): void {
@@ -263,22 +263,20 @@ export class SearchView extends ViewPane {
this._saveSearchHistoryService();
}));
this._register(this.storageService.onDidChangeValue((v) => {
if (v.key === SearchHistoryService.SEARCH_HISTORY_KEY) {
const restoredHistory = this.searchHistoryService.load();
this._register(this.storageService.onDidChangeValue(StorageScope.WORKSPACE, SearchHistoryService.SEARCH_HISTORY_KEY, this._register(new DisposableStore()))(() => {
const restoredHistory = this.searchHistoryService.load();
if (restoredHistory.include) {
this.inputPatternIncludes.prependHistory(restoredHistory.include);
}
if (restoredHistory.exclude) {
this.inputPatternExcludes.prependHistory(restoredHistory.exclude);
}
if (restoredHistory.search) {
this.searchWidget.prependSearchHistory(restoredHistory.search);
}
if (restoredHistory.replace) {
this.searchWidget.prependReplaceHistory(restoredHistory.replace);
}
if (restoredHistory.include) {
this.inputPatternIncludes.prependHistory(restoredHistory.include);
}
if (restoredHistory.exclude) {
this.inputPatternExcludes.prependHistory(restoredHistory.exclude);
}
if (restoredHistory.search) {
this.searchWidget.prependSearchHistory(restoredHistory.search);
}
if (restoredHistory.replace) {
this.searchWidget.prependReplaceHistory(restoredHistory.replace);
}
}));
}
@@ -43,7 +43,7 @@ suite('extractRangeFromFilter', () => {
assert.strictEqual(res?.range.startColumn, 20);
});
suite('unless', async function () {
suite('unless', function () {
const testSpecs = [
// alpha-only symbol after unless
{ filter: '/some/path/file.txt@alphasymbol', unless: ['@'], result: undefined },
@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import { env } from 'vs/base/common/process';
import { Disposable } from 'vs/base/common/lifecycle';
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
import { LRUCache } from 'vs/base/common/map';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { FileOperationError, FileOperationResult, IFileContent, IFileService } from 'vs/platform/files/common/files';
@@ -128,18 +128,18 @@ export class TerminalPersistedHistory<T> extends Disposable implements ITerminal
this._entries = new LRUCache<string, T>(this._getHistoryLimit());
// Listen for config changes to set history limit
this._configurationService.onDidChangeConfiguration(e => {
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(TerminalSettingId.ShellIntegrationCommandHistory)) {
this._entries.limit = this._getHistoryLimit();
}
});
}));
// Listen to cache changes from other windows
this._storageService.onDidChangeValue(e => {
if (e.key === this._getTimestampStorageKey() && !this._isStale) {
this._register(this._storageService.onDidChangeValue(StorageScope.APPLICATION, this._getTimestampStorageKey(), this._register(new DisposableStore()))(() => {
if (!this._isStale) {
this._isStale = this._storageService.getNumber(this._getTimestampStorageKey(), StorageScope.APPLICATION, 0) !== this._timestamp;
}
});
}));
}
add(key: string, value: T) {
@@ -71,7 +71,7 @@ suite('DecorationAddon', () => {
instantiationService.dispose();
});
suite('registerDecoration', async () => {
suite('registerDecoration', () => {
test('should throw when command has no marker', async () => {
throws(() => decorationAddon.registerCommandDecoration({ command: 'cd src', timestamp: Date.now(), hasOutput: () => false } as ITerminalCommand));
});
@@ -39,7 +39,7 @@ suite('ShellIntegrationAddon', () => {
capabilities = shellIntegrationAddon.capabilities;
});
suite('cwd detection', async () => {
suite('cwd detection', () => {
test('should activate capability on the cwd sequence (OSC 633 ; P ; Cwd=<cwd> ST)', async () => {
strictEqual(capabilities.has(TerminalCapability.CwdDetection), false);
await writeP(xterm, 'foo');
@@ -70,7 +70,7 @@ suite('ShellIntegrationAddon', () => {
}
});
suite('detect `SetCwd` sequence: `OSC 7; scheme://cwd ST`', async () => {
suite('detect `SetCwd` sequence: `OSC 7; scheme://cwd ST`', () => {
test('should accept well-formatted URLs', async () => {
type TestCase = [title: string, input: string, expected: string];
const cases: TestCase[] = [
@@ -133,7 +133,7 @@ suite('ShellIntegrationAddon', () => {
});
});
suite('command tracking', async () => {
suite('command tracking', () => {
test('should activate capability on the prompt start sequence (OSC 633 ; A ST)', async () => {
strictEqual(capabilities.has(TerminalCapability.CommandDetection), false);
await writeP(xterm, 'foo');
@@ -212,7 +212,7 @@ suite('ShellIntegrationAddon', () => {
mock.verify();
});
});
suite('BufferMarkCapability', async () => {
suite('BufferMarkCapability', () => {
test('SetMark', async () => {
strictEqual(capabilities.has(TerminalCapability.BufferMarkDetection), false);
await writeP(xterm, 'foo');
@@ -160,7 +160,7 @@ suite('Terminal history', () => {
});
if (!isWindows) {
suite('local', async () => {
suite('local', () => {
let originalEnvValues: { HOME: string | undefined };
setup(() => {
originalEnvValues = { HOME: env['HOME'] };
@@ -344,7 +344,7 @@ suite('Terminal history', () => {
instantiationService.dispose();
});
suite('local', async () => {
suite('local', () => {
let originalEnvValues: { HOME: string | undefined; APPDATA: string | undefined };
setup(() => {
originalEnvValues = { HOME: env['HOME'], APPDATA: env['APPDATA'] };
@@ -92,7 +92,7 @@ suite('Workbench - TerminalProfiles', () => {
const expected = [{ profileName: 'Git Bash', path: 'C:\\Program Files\\Git\\bin\\bash.exe', args: [], isAutoDetected: undefined, overrideName: undefined, isDefault: true }];
profilesEqual(profiles, expected);
});
suite('pwsh source detection/fallback', async () => {
suite('pwsh source detection/fallback', () => {
const pwshSourceConfig = ({
profiles: {
windows: {
@@ -73,7 +73,7 @@ suite('QuickFixAddon', () => {
instantiationService.dispose();
});
suite('registerCommandFinishedListener & getMatchActions', () => {
suite('gitSimilarCommand', async () => {
suite('gitSimilarCommand', () => {
const expectedMap = new Map();
const command = `git sttatus`;
let output = `git: 'sttatus' is not a git command. See 'git --help'.
@@ -149,7 +149,7 @@ suite('QuickFixAddon', () => {
});
});
});
suite('gitTwoDashes', async () => {
suite('gitTwoDashes', () => {
const expectedMap = new Map();
const command = `git add . -all`;
const output = 'error: did you mean `--all` (with two dashes)?';

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