Merge branch 'main' into tyriar/links_contrib

This commit is contained in:
Daniel Imms 2023-03-02 08:52:27 -08:00 committed by GitHub
commit ade8346118
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
108 changed files with 2761 additions and 468 deletions

View file

@ -51,7 +51,7 @@
"editor-find": {"assign": ["rebornix"]},
"editor-folding": {"assign": ["aeschli"]},
"editor-highlight": {"assign": ["alexdima"]},
"editor-hover": {"assign": ["alexdima"]},
"editor-hover": {"assign": ["aiday-mar"]},
"editor-indent-detection": {"assign": ["alexdima"]},
"editor-indent-guides": {"assign": ["hediet"]},
"editor-input": {"assign": ["alexdima"]},
@ -65,7 +65,7 @@
"editor-RTL": {"assign": ["alexdima"]},
"editor-scrollbar": {"assign": ["alexdima"]},
"editor-sorting": {"assign": ["alexdima"]},
"editor-sticky-scroll": {"assign": ["jrieken"]},
"editor-sticky-scroll": {"assign": ["aiday-mar"]},
"editor-symbols": {"assign": ["jrieken"]},
"editor-synced-region": {"assign": ["aeschli"]},
"editor-textbuffer": {"assign": ["alexdima", "rebornix"]},
@ -114,6 +114,7 @@
"issue-reporter": {"assign": ["TylerLeonhardt"]},
"javascript": {"assign": ["mjbvz"]},
"json": {"assign": ["aeschli"]},
"json-sorting": {"assign": ["aiday-mar"]},
"keybindings": {"assign": ["alexdima"]},
"keybindings-editor": {"assign": ["sandy081"]},
"keyboard-layout": {"assign": ["alexdima"]},

2
.nvmrc
View file

@ -1 +1 @@
16.17
16.14

View file

@ -1,4 +1,4 @@
disturl "https://electronjs.org/headers"
target "22.3.1"
target "19.1.9"
runtime "electron"
build_from_source "true"

View file

@ -170,7 +170,7 @@ steps:
if [ -z "$CC" ] || [ -z "$CXX" ]; then
# Download clang based on chromium revision used by vscode
curl -s https://raw.githubusercontent.com/chromium/chromium/108.0.5359.215/tools/clang/scripts/update.py | python - --output-dir=$PWD/.build/CR_Clang --host-os=linux
curl -s https://raw.githubusercontent.com/chromium/chromium/98.0.4758.109/tools/clang/scripts/update.py | python - --output-dir=$PWD/.build/CR_Clang --host-os=linux
# Download libcxx headers and objects from upstream electron releases
DEBUG=libcxx-fetcher \
VSCODE_LIBCXX_OBJECTS_DIR=$PWD/.build/libcxx-objects \
@ -180,12 +180,12 @@ steps:
node build/linux/libcxx-fetcher.js
# Set compiler toolchain
# Flags for the client build are based on
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/108.0.5359.215:build/config/arm.gni
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/108.0.5359.215:build/config/compiler/BUILD.gn
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/108.0.5359.215:build/config/c++/BUILD.gn
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:build/config/arm.gni
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:build/config/compiler/BUILD.gn
# https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:build/config/c++/BUILD.gn
export CC=$PWD/.build/CR_Clang/bin/clang
export CXX=$PWD/.build/CR_Clang/bin/clang++
export CXXFLAGS="-nostdinc++ -D__NO_INLINE__ -I$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit -D_LIBCPP_ABI_NAMESPACE=Cr"
export CXXFLAGS="-nostdinc++ -D__NO_INLINE__ -isystem$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit"
export LDFLAGS="-stdlib=libc++ -fuse-ld=lld -flto=thin -L$PWD/.build/libcxx-objects -lc++abi -Wl,--lto-O0"
export VSCODE_REMOTE_CC=$(which gcc)
export VSCODE_REMOTE_CXX=$(which g++)

View file

@ -6,7 +6,6 @@ schedules:
branches:
include:
- main
- joao/web
trigger:
branches:
@ -153,11 +152,11 @@ resources:
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: vscode-arm64
image: vscodehub.azurecr.io/vscode-linux-build-agent:buster-arm64
image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-arm64
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: vscode-armhf
image: vscodehub.azurecr.io/vscode-linux-build-agent:buster-armhf
image: vscodehub.azurecr.io/vscode-linux-build-agent:stretch-armhf
endpoint: VSCodeHub
options: --user 0:0 --cap-add SYS_ADMIN
- container: centos7-devtoolset8-x64

View file

@ -259,7 +259,7 @@ stages:
# Set compiler toolchain
export CC=$PWD/.build/CR_Clang/bin/clang
export CXX=$PWD/.build/CR_Clang/bin/clang++
export CXXFLAGS="-std=c++17 -nostdinc++ -D__NO_INLINE__ -I$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit -D_LIBCPP_ABI_NAMESPACE=Cr"
export CXXFLAGS="-nostdinc++ -D__NO_INLINE__ -isystem$PWD/.build/libcxx_headers -isystem$PWD/.build/libcxx_headers/include -isystem$PWD/.build/libcxxabi_headers/include -fPIC -flto=thin -fsplit-lto-unit"
export LDFLAGS="-stdlib=libc++ -fuse-ld=lld -flto=thin -fsplit-lto-unit -L$PWD/.build/libcxx-objects -lc++abi"
export VSCODE_REMOTE_CC=$(which gcc)
export VSCODE_REMOTE_CXX=$(which g++)

File diff suppressed because one or more lines are too long

View file

@ -125,7 +125,7 @@ export function compileTask(src: string, out: string, build: boolean): () => Nod
let mangleStream = es.through();
if (build) {
let ts2tsMangler = new Mangler(compile.projectPath, (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data));
const newContentsByFileName = ts2tsMangler.computeNewFileContents();
const newContentsByFileName = ts2tsMangler.computeNewFileContents(new Set(['saveState']));
mangleStream = es.through(function write(data: File & { sourceMap?: RawSourceMap }) {
type TypeScriptExt = typeof ts & { normalizePath(path: string): string };
const tsNormalPath = (<TypeScriptExt>ts).normalizePath(data.path);

View file

@ -76,7 +76,7 @@ function darwinBundleDocumentTypes(types, icon) {
});
}
exports.config = {
version: product.electronRepository ? '22.10.0' : util.getElectronVersion(),
version: product.electronRepository ? '19.1.11' : util.getElectronVersion(),
productAppName: product.nameLong,
companyName: 'Microsoft Corporation',
copyright: 'Copyright (C) 2022 Microsoft. All rights reserved',
@ -193,7 +193,7 @@ function getElectron(arch) {
};
}
async function main(arch = process.arch) {
const version = product.electronRepository ? '22.10.0' : util.getElectronVersion();
const version = product.electronRepository ? '19.1.11' : util.getElectronVersion();
const electronPath = path.join(root, '.build', 'electron');
const versionFile = path.join(electronPath, 'version');
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;

View file

@ -91,7 +91,7 @@ function darwinBundleDocumentTypes(types: { [name: string]: string | string[] },
}
export const config = {
version: product.electronRepository ? '22.10.0' : util.getElectronVersion(),
version: product.electronRepository ? '19.1.11' : util.getElectronVersion(),
productAppName: product.nameLong,
companyName: 'Microsoft Corporation',
copyright: 'Copyright (C) 2022 Microsoft. All rights reserved',
@ -212,7 +212,7 @@ function getElectron(arch: string): () => NodeJS.ReadWriteStream {
}
async function main(arch = process.arch): Promise<void> {
const version = product.electronRepository ? '22.10.0' : util.getElectronVersion();
const version = product.electronRepository ? '19.1.11' : util.getElectronVersion();
const electronPath = path.join(root, '.build', 'electron');
const versionFile = path.join(electronPath, 'version');
const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`;

File diff suppressed because one or more lines are too long

View file

@ -81,6 +81,12 @@ const RULES: IRule[] = [
skip: true // -> skip all test files
},
// TODO@bpasero remove me once electron utility process has landed
{
target: '**/vs/workbench/services/extensions/electron-sandbox/nativeLocalProcessExtensionHost.ts',
skip: true
},
// Common: vs/base/common/platform.ts
{
target: '**/vs/base/common/platform.ts',

File diff suppressed because one or more lines are too long

View file

@ -145,7 +145,7 @@ class ClassData {
;
}
static makeImplicitPublicActuallyPublic(data: ClassData, reportViolation: (what: string, why: string) => void): void {
static makeImplicitPublicActuallyPublic(data: ClassData, reportViolation: (name: string, what: string, why: string) => void): void {
// TS-HACK
// A subtype can make an inherited protected field public. To prevent accidential
// mangling of public fields we mark the original (protected) fields as public...
@ -158,7 +158,7 @@ class ClassData {
if (parent.fields.get(name)?.type === FieldType.Protected) {
const parentPos = parent.node.getSourceFile().getLineAndCharacterOfPosition(parent.fields.get(name)!.pos);
const infoPos = data.node.getSourceFile().getLineAndCharacterOfPosition(info.pos);
reportViolation(`'${name}' from ${parent.fileName}:${parentPos.line + 1}`, `${data.fileName}:${infoPos.line + 1}`);
reportViolation(name, `'${name}' from ${parent.fileName}:${parentPos.line + 1}`, `${data.fileName}:${infoPos.line + 1}`);
parent.fields.get(name)!.type = FieldType.Public;
}
@ -346,7 +346,7 @@ export class Mangler {
this.service = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
}
computeNewFileContents(): Map<string, MangleOutput> {
computeNewFileContents(strictImplicitPublicHandling?: Set<string>): Map<string, MangleOutput> {
// STEP: find all classes and their field info
@ -405,19 +405,29 @@ export class Mangler {
// STEP: make implicit public (actually protected) field really public
const violations = new Map<string, string[]>();
let violationsCauseFailure = false;
for (const data of this.allClassDataByKey.values()) {
ClassData.makeImplicitPublicActuallyPublic(data, (what, why) => {
ClassData.makeImplicitPublicActuallyPublic(data, (name: string, what, why) => {
const arr = violations.get(what);
if (arr) {
arr.push(why);
} else {
violations.set(what, [why]);
}
if (strictImplicitPublicHandling && !strictImplicitPublicHandling.has(name)) {
violationsCauseFailure = true;
}
});
}
for (const [why, whys] of violations) {
this.log(`WARN: ${why} became PUBLIC because of: ${whys.join(' , ')}`);
}
if (violationsCauseFailure) {
const message = 'Protected fields have been made PUBLIC. This hurts minification and is therefore not allowed. Review the WARN messages further above';
this.log(`ERROR: ${message}`);
throw new Error(message);
}
// STEP: compute replacement names for each class
for (const data of this.allClassDataByKey.values()) {
@ -579,7 +589,7 @@ async function _run() {
const projectBase = path.dirname(projectPath);
const newProjectBase = path.join(path.dirname(projectBase), path.basename(projectBase) + '2');
for await (const [fileName, contents] of new Mangler(projectPath, console.log).computeNewFileContents()) {
for await (const [fileName, contents] of new Mangler(projectPath, console.log).computeNewFileContents(new Set(['saveState']))) {
const newFilePath = path.join(newProjectBase, path.relative(projectBase, fileName));
await fs.promises.mkdir(path.dirname(newFilePath), { recursive: true });
await fs.promises.writeFile(newFilePath, contents.out);

View file

@ -23,7 +23,7 @@ exports.recommendedDeps = [
exports.referenceGeneratedDepsByArch = {
'amd64': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
@ -34,9 +34,9 @@ exports.referenceGeneratedDepsByArch = {
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.5.12)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -60,20 +60,20 @@ exports.referenceGeneratedDepsByArch = {
],
'armhf': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.5.12)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -84,7 +84,6 @@ exports.referenceGeneratedDepsByArch = {
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
'libx11-6',
@ -101,18 +100,20 @@ exports.referenceGeneratedDepsByArch = {
],
'arm64': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.0.2)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc1 (>= 1:4.2)',
'libgcc1 (>= 1:4.5)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -123,7 +124,6 @@ exports.referenceGeneratedDepsByArch = {
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
'libx11-6',
@ -139,4 +139,4 @@ exports.referenceGeneratedDepsByArch = {
'xdg-utils (>= 1.0.2)'
]
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGtCQUFrQjtRQUNsQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHlCQUF5QjtRQUN6QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6QixVQUFVO1FBQ1YsMEJBQTBCO1FBQzFCLG9CQUFvQjtRQUNwQiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLFVBQVU7UUFDVixZQUFZO1FBQ1osMEJBQTBCO1FBQzFCLGFBQWE7UUFDYixZQUFZO1FBQ1osc0JBQXNCO0tBQ3RCO0lBQ0QsT0FBTyxFQUFFO1FBQ1IsaUJBQWlCO1FBQ2pCLHdCQUF3QjtRQUN4QiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLDJCQUEyQjtRQUMzQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGdCQUFnQjtRQUNoQixnQkFBZ0I7UUFDaEIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx5QkFBeUI7UUFDekIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsdUJBQXVCO1FBQ3ZCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsdUJBQXVCO1FBQ3ZCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7Q0FDRCxDQUFDIn0=
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGtCQUFrQjtRQUNsQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHlCQUF5QjtRQUN6QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLG9CQUFvQjtRQUNwQiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6QixVQUFVO1FBQ1YsMEJBQTBCO1FBQzFCLG9CQUFvQjtRQUNwQiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLFVBQVU7UUFDVixZQUFZO1FBQ1osMEJBQTBCO1FBQzFCLGFBQWE7UUFDYixZQUFZO1FBQ1osc0JBQXNCO0tBQ3RCO0lBQ0QsT0FBTyxFQUFFO1FBQ1IsaUJBQWlCO1FBQ2pCLHdCQUF3QjtRQUN4QiwrQkFBK0I7UUFDL0Isd0JBQXdCO1FBQ3hCLDJCQUEyQjtRQUMzQixpQkFBaUI7UUFDakIsaUJBQWlCO1FBQ2pCLGdCQUFnQjtRQUNoQixnQkFBZ0I7UUFDaEIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx5QkFBeUI7UUFDekIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0QixvQkFBb0I7UUFDcEIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsdUJBQXVCO1FBQ3ZCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIsb0JBQW9CO1FBQ3BCLG9CQUFvQjtRQUNwQixvQkFBb0I7UUFDcEIsb0JBQW9CO1FBQ3BCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLHVCQUF1QjtRQUN2QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7Q0FDRCxDQUFDIn0=

View file

@ -23,7 +23,7 @@ export const recommendedDeps = [
export const referenceGeneratedDepsByArch = {
'amd64': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
@ -34,9 +34,9 @@ export const referenceGeneratedDepsByArch = {
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.5.12)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -60,20 +60,20 @@ export const referenceGeneratedDepsByArch = {
],
'armhf': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.15)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libc6 (>= 2.4)',
'libc6 (>= 2.9)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.5.12)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -84,7 +84,6 @@ export const referenceGeneratedDepsByArch = {
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
'libx11-6',
@ -101,18 +100,20 @@ export const referenceGeneratedDepsByArch = {
],
'arm64': [
'ca-certificates',
'libasound2 (>= 1.0.17)',
'libasound2 (>= 1.0.16)',
'libatk-bridge2.0-0 (>= 2.5.3)',
'libatk1.0-0 (>= 2.2.0)',
'libatspi2.0-0 (>= 2.9.90)',
'libc6 (>= 2.17)',
'libc6 (>= 2.28)',
'libcairo2 (>= 1.6.0)',
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
'libdbus-1-3 (>= 1.0.2)',
'libdrm2 (>= 2.4.60)',
'libdrm2 (>= 2.4.38)',
'libexpat1 (>= 2.0.1)',
'libgbm1 (>= 17.1.0~rc2)',
'libgbm1 (>= 8.1~0)',
'libgcc1 (>= 1:3.0)',
'libgcc1 (>= 1:4.2)',
'libgcc1 (>= 1:4.5)',
'libglib2.0-0 (>= 2.16.0)',
'libglib2.0-0 (>= 2.39.4)',
'libgtk-3-0 (>= 3.9.10)',
@ -123,7 +124,6 @@ export const referenceGeneratedDepsByArch = {
'libpango-1.0-0 (>= 1.14.0)',
'libsecret-1-0 (>= 0.18)',
'libstdc++6 (>= 4.1.1)',
'libstdc++6 (>= 5)',
'libstdc++6 (>= 5.2)',
'libstdc++6 (>= 6)',
'libx11-6',

View file

@ -21,13 +21,15 @@ const types_2 = require("./rpm/types");
// The reference dependencies, which one has to update when the new dependencies
// are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES = true;
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/108.0.5359.215:chrome/installer/linux/BUILD.gn;l=64-80
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80
// and the Linux Archive build
// Shared library dependencies that we already bundle.
const bundledDeps = [
'libEGL.so',
'libGLESv2.so',
'libvulkan.so.1',
'swiftshader_libEGL.so',
'swiftshader_libGLESv2.so',
'libvk_swiftshader.so',
'libffmpeg.so'
];
@ -97,4 +99,4 @@ function mergePackageDeps(inputDeps) {
}
return requires;
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwZW5kZW5jaWVzLWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRlcGVuZGVuY2llcy1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztnR0FHZ0c7QUFFaEcsWUFBWSxDQUFDOzs7QUFFYixpREFBMEM7QUFDMUMsNkJBQThCO0FBQzlCLDREQUEyRjtBQUMzRix5REFBcUY7QUFDckYsa0RBQXlGO0FBQ3pGLCtDQUFtRjtBQUNuRiwwQ0FBc0U7QUFDdEUsdUNBQTZEO0FBRTdELHFDQUFxQztBQUNyQyxxRUFBcUU7QUFDckUsMkRBQTJEO0FBQzNELHlEQUF5RDtBQUN6RCxtRkFBbUY7QUFDbkYsZ0ZBQWdGO0FBQ2hGLGlDQUFpQztBQUNqQyxNQUFNLCtCQUErQixHQUFZLElBQUksQ0FBQztBQUV0RCxnSUFBZ0k7QUFDaEksOEJBQThCO0FBQzlCLHNEQUFzRDtBQUN0RCxNQUFNLFdBQVcsR0FBRztJQUNuQixXQUFXO0lBQ1gsY0FBYztJQUNkLGdCQUFnQjtJQUNoQixzQkFBc0I7SUFDdEIsY0FBYztDQUNkLENBQUM7QUFFRixTQUFnQixlQUFlLENBQUMsV0FBMEIsRUFBRSxRQUFnQixFQUFFLGVBQXVCLEVBQUUsSUFBWSxFQUFFLE9BQWdCO0lBQ3BJLElBQUksV0FBVyxLQUFLLEtBQUssRUFBRTtRQUMxQixJQUFJLENBQUMsSUFBQSwwQkFBa0IsRUFBQyxJQUFJLENBQUMsRUFBRTtZQUM5QixNQUFNLElBQUksS0FBSyxDQUFDLDZCQUE2QixHQUFHLElBQUksQ0FBQyxDQUFDO1NBQ3REO1FBQ0QsSUFBSSxDQUFDLE9BQU8sRUFBRTtZQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsMkJBQTJCLENBQUMsQ0FBQztTQUM3QztLQUNEO0lBQ0QsSUFBSSxXQUFXLEtBQUssS0FBSyxJQUFJLENBQUMsSUFBQSx1QkFBZSxFQUFDLElBQUksQ0FBQyxFQUFFO1FBQ3BELE1BQU0sSUFBSSxLQUFLLENBQUMsMEJBQTBCLEdBQUcsSUFBSSxDQUFDLENBQUM7S0FDbkQ7SUFFRCx3REFBd0Q7SUFDeEQsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLDRCQUE0QixDQUFDLENBQUM7SUFDaEcsTUFBTSxVQUFVLEdBQUcsSUFBQSx5QkFBUyxFQUFDLE1BQU0sRUFBRSxDQUFDLGlCQUFpQixFQUFFLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQyxDQUFDO0lBQzdFLElBQUksVUFBVSxDQUFDLE1BQU0sRUFBRTtRQUN0QixPQUFPLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUM7UUFDdEMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7UUFDNUMsT0FBTyxFQUFFLENBQUM7S0FDVjtJQUVELE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDO0lBRWpFLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLGVBQWUsQ0FBQyxDQUFDO0lBQ3JELEtBQUssQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFcEIsMkNBQTJDO0lBQzNDLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDO0lBQ2xELEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUseUJBQXlCLENBQUMsQ0FBQyxDQUFDO0lBRTNELDZCQUE2QjtJQUM3QixNQUFNLFlBQVksR0FBRyxXQUFXLEtBQUssS0FBSyxDQUFDLENBQUM7UUFDM0MsSUFBQSxvQ0FBeUIsRUFBQyxLQUFLLEVBQUUsSUFBd0IsRUFBRSxPQUFRLENBQUMsQ0FBQyxDQUFDO1FBQ3RFLElBQUEsb0NBQXNCLEVBQUMsS0FBSyxDQUFDLENBQUM7SUFFL0IsOEJBQThCO0lBQzlCLE1BQU0sa0JBQWtCLEdBQUcsZ0JBQWdCLENBQUMsWUFBWSxDQUFDLENBQUM7SUFFMUQsd0NBQXdDO0lBQ3hDLE1BQU0sa0JBQWtCLEdBQWEsS0FBSyxDQUFDLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsRUFBRTtRQUN2RixPQUFPLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztJQUMzRSxDQUFDLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUVWLE1BQU0sc0JBQXNCLEdBQUcsV0FBVyxLQUFLLEtBQUssQ0FBQyxDQUFDO1FBQ3JELHdDQUFtQixDQUFDLElBQXdCLENBQUMsQ0FBQyxDQUFDO1FBQy9DLHdDQUFnQixDQUFDLElBQXFCLENBQUMsQ0FBQztJQUN6QyxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUMsS0FBSyxJQUFJLENBQUMsU0FBUyxDQUFDLHNCQUFzQixDQUFDLEVBQUU7UUFDbEYsTUFBTSxXQUFXLEdBQUcsb0NBQW9DO2NBQ3JELFVBQVUsR0FBRyxzQkFBc0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2NBQzlDLFVBQVUsR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDOUMsSUFBSSwrQkFBK0IsRUFBRTtZQUNwQyxNQUFNLElBQUksS0FBSyxDQUFDLFdBQVcsQ0FBQyxDQUFDO1NBQzdCO2FBQU07WUFDTixPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1NBQzFCO0tBQ0Q7SUFFRCxPQUFPLGtCQUFrQixDQUFDO0FBQzNCLENBQUM7QUEzREQsMENBMkRDO0FBR0Qsc0hBQXNIO0FBQ3RILFNBQVMsZ0JBQWdCLENBQUMsU0FBd0I7SUFDakQsTUFBTSxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztJQUNuQyxLQUFLLE1BQU0sTUFBTSxJQUFJLFNBQVMsRUFBRTtRQUMvQixLQUFLLE1BQU0sR0FBRyxJQUFJLE1BQU0sRUFBRTtZQUN6QixNQUFNLGlCQUFpQixHQUFHLEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUNyQyxJQUFJLGlCQUFpQixDQUFDLE1BQU0sSUFBSSxDQUFDLGlCQUFpQixDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRTtnQkFDbkUsUUFBUSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO2FBQ2hDO1NBQ0Q7S0FDRDtJQUNELE9BQU8sUUFBUSxDQUFDO0FBQ2pCLENBQUMifQ==
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwZW5kZW5jaWVzLWdlbmVyYXRvci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRlcGVuZGVuY2llcy1nZW5lcmF0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7OztnR0FHZ0c7QUFFaEcsWUFBWSxDQUFDOzs7QUFFYixpREFBMEM7QUFDMUMsNkJBQThCO0FBQzlCLDREQUEyRjtBQUMzRix5REFBcUY7QUFDckYsa0RBQXlGO0FBQ3pGLCtDQUFtRjtBQUNuRiwwQ0FBc0U7QUFDdEUsdUNBQTZEO0FBRTdELHFDQUFxQztBQUNyQyxxRUFBcUU7QUFDckUsMkRBQTJEO0FBQzNELHlEQUF5RDtBQUN6RCxtRkFBbUY7QUFDbkYsZ0ZBQWdGO0FBQ2hGLGlDQUFpQztBQUNqQyxNQUFNLCtCQUErQixHQUFZLElBQUksQ0FBQztBQUV0RCwrSEFBK0g7QUFDL0gsOEJBQThCO0FBQzlCLHNEQUFzRDtBQUN0RCxNQUFNLFdBQVcsR0FBRztJQUNuQixXQUFXO0lBQ1gsY0FBYztJQUNkLGdCQUFnQjtJQUNoQix1QkFBdUI7SUFDdkIsMEJBQTBCO0lBQzFCLHNCQUFzQjtJQUN0QixjQUFjO0NBQ2QsQ0FBQztBQUVGLFNBQWdCLGVBQWUsQ0FBQyxXQUEwQixFQUFFLFFBQWdCLEVBQUUsZUFBdUIsRUFBRSxJQUFZLEVBQUUsT0FBZ0I7SUFDcEksSUFBSSxXQUFXLEtBQUssS0FBSyxFQUFFO1FBQzFCLElBQUksQ0FBQyxJQUFBLDBCQUFrQixFQUFDLElBQUksQ0FBQyxFQUFFO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkJBQTZCLEdBQUcsSUFBSSxDQUFDLENBQUM7U0FDdEQ7UUFDRCxJQUFJLENBQUMsT0FBTyxFQUFFO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1NBQzdDO0tBQ0Q7SUFDRCxJQUFJLFdBQVcsS0FBSyxLQUFLLElBQUksQ0FBQyxJQUFBLHVCQUFlLEVBQUMsSUFBSSxDQUFDLEVBQUU7UUFDcEQsTUFBTSxJQUFJLEtBQUssQ0FBQywwQkFBMEIsR0FBRyxJQUFJLENBQUMsQ0FBQztLQUNuRDtJQUVELHdEQUF3RDtJQUN4RCxNQUFNLGlCQUFpQixHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsNEJBQTRCLENBQUMsQ0FBQztJQUNoRyxNQUFNLFVBQVUsR0FBRyxJQUFBLHlCQUFTLEVBQUMsTUFBTSxFQUFFLENBQUMsaUJBQWlCLEVBQUUsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7SUFDN0UsSUFBSSxVQUFVLENBQUMsTUFBTSxFQUFFO1FBQ3RCLE9BQU8sQ0FBQyxLQUFLLENBQUMsc0JBQXNCLENBQUMsQ0FBQztRQUN0QyxPQUFPLENBQUMsS0FBSyxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQztRQUM1QyxPQUFPLEVBQUUsQ0FBQztLQUNWO0lBRUQsTUFBTSxLQUFLLEdBQUcsVUFBVSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFakUsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUUsZUFBZSxDQUFDLENBQUM7SUFDckQsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUVwQiwyQ0FBMkM7SUFDM0MsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUM7SUFDbEQsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSx5QkFBeUIsQ0FBQyxDQUFDLENBQUM7SUFFM0QsNkJBQTZCO0lBQzdCLE1BQU0sWUFBWSxHQUFHLFdBQVcsS0FBSyxLQUFLLENBQUMsQ0FBQztRQUMzQyxJQUFBLG9DQUF5QixFQUFDLEtBQUssRUFBRSxJQUF3QixFQUFFLE9BQVEsQ0FBQyxDQUFDLENBQUM7UUFDdEUsSUFBQSxvQ0FBc0IsRUFBQyxLQUFLLENBQUMsQ0FBQztJQUUvQiw4QkFBOEI7SUFDOUIsTUFBTSxrQkFBa0IsR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUUxRCx3Q0FBd0M7SUFDeEMsTUFBTSxrQkFBa0IsR0FBYSxLQUFLLENBQUMsSUFBSSxDQUFDLGtCQUFrQixDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxFQUFFO1FBQ3ZGLE9BQU8sQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDO0lBQzNFLENBQUMsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDO0lBRVYsTUFBTSxzQkFBc0IsR0FBRyxXQUFXLEtBQUssS0FBSyxDQUFDLENBQUM7UUFDckQsd0NBQW1CLENBQUMsSUFBd0IsQ0FBQyxDQUFDLENBQUM7UUFDL0Msd0NBQWdCLENBQUMsSUFBcUIsQ0FBQyxDQUFDO0lBQ3pDLElBQUksSUFBSSxDQUFDLFNBQVMsQ0FBQyxrQkFBa0IsQ0FBQyxLQUFLLElBQUksQ0FBQyxTQUFTLENBQUMsc0JBQXNCLENBQUMsRUFBRTtRQUNsRixNQUFNLFdBQVcsR0FBRyxvQ0FBb0M7Y0FDckQsVUFBVSxHQUFHLHNCQUFzQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7Y0FDOUMsVUFBVSxHQUFHLGtCQUFrQixDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUM5QyxJQUFJLCtCQUErQixFQUFFO1lBQ3BDLE1BQU0sSUFBSSxLQUFLLENBQUMsV0FBVyxDQUFDLENBQUM7U0FDN0I7YUFBTTtZQUNOLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7U0FDMUI7S0FDRDtJQUVELE9BQU8sa0JBQWtCLENBQUM7QUFDM0IsQ0FBQztBQTNERCwwQ0EyREM7QUFHRCxzSEFBc0g7QUFDdEgsU0FBUyxnQkFBZ0IsQ0FBQyxTQUF3QjtJQUNqRCxNQUFNLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBVSxDQUFDO0lBQ25DLEtBQUssTUFBTSxNQUFNLElBQUksU0FBUyxFQUFFO1FBQy9CLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxFQUFFO1lBQ3pCLE1BQU0saUJBQWlCLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ3JDLElBQUksaUJBQWlCLENBQUMsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxFQUFFO2dCQUNuRSxRQUFRLENBQUMsR0FBRyxDQUFDLGlCQUFpQixDQUFDLENBQUM7YUFDaEM7U0FDRDtLQUNEO0lBQ0QsT0FBTyxRQUFRLENBQUM7QUFDakIsQ0FBQyJ9

View file

@ -23,13 +23,15 @@ import { isRpmArchString, RpmArchString } from './rpm/types';
// are valid, are in dep-lists.ts
const FAIL_BUILD_FOR_NEW_DEPENDENCIES: boolean = true;
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/108.0.5359.215:chrome/installer/linux/BUILD.gn;l=64-80
// Based on https://source.chromium.org/chromium/chromium/src/+/refs/tags/98.0.4758.109:chrome/installer/linux/BUILD.gn;l=64-80
// and the Linux Archive build
// Shared library dependencies that we already bundle.
const bundledDeps = [
'libEGL.so',
'libGLESv2.so',
'libvulkan.so.1',
'swiftshader_libEGL.so',
'swiftshader_libGLESv2.so',
'libvk_swiftshader.so',
'libffmpeg.so'
];

File diff suppressed because one or more lines are too long

View file

@ -122,11 +122,10 @@ export const referenceGeneratedDepsByArch = {
'libc.so.6',
'libc.so.6(GLIBC_2.10)',
'libc.so.6(GLIBC_2.11)',
'libc.so.6(GLIBC_2.14)',
'libc.so.6(GLIBC_2.15)',
'libc.so.6(GLIBC_2.16)',
'libc.so.6(GLIBC_2.17)',
'libc.so.6(GLIBC_2.25)',
'libc.so.6(GLIBC_2.28)',
'libc.so.6(GLIBC_2.4)',
'libc.so.6(GLIBC_2.6)',
'libc.so.6(GLIBC_2.7)',
@ -142,6 +141,7 @@ export const referenceGeneratedDepsByArch = {
'libgbm.so.1',
'libgcc_s.so.1',
'libgcc_s.so.1(GCC_3.0)',
'libgcc_s.so.1(GCC_3.4)',
'libgcc_s.so.1(GCC_3.5)',
'libgio-2.0.so.0',
'libglib-2.0.so.0',
@ -219,8 +219,6 @@ export const referenceGeneratedDepsByArch = {
'libatspi.so.0()(64bit)',
'libc.so.6()(64bit)',
'libc.so.6(GLIBC_2.17)(64bit)',
'libc.so.6(GLIBC_2.25)(64bit)',
'libc.so.6(GLIBC_2.28)(64bit)',
'libcairo.so.2()(64bit)',
'libcurl.so.4()(64bit)',
'libdbus-1.so.3()(64bit)',

View file

@ -9,8 +9,8 @@ const majorNodeVersion = parseInt(nodeVersion[1]);
const minorNodeVersion = parseInt(nodeVersion[2]);
const patchNodeVersion = parseInt(nodeVersion[3]);
if (majorNodeVersion < 16 || (majorNodeVersion === 16 && minorNodeVersion < 17)) {
console.error('\033[1;31m*** Please use node.js versions >=16.17.x and <17.\033[0;0m');
if (majorNodeVersion < 16 || (majorNodeVersion === 16 && minorNodeVersion < 14)) {
console.error('\033[1;31m*** Please use node.js versions >=16.14.x and <17.\033[0;0m');
err = true;
}
if (majorNodeVersion >= 17) {

View file

@ -6,7 +6,7 @@
"git": {
"name": "chromium",
"repositoryUrl": "https://chromium.googlesource.com/chromium/src",
"commitHash": "513ac8b2c47c7e1ac6b9f4fb5ea98e965cf29b66"
"commitHash": "61305fe71c4357662f161ba689fd9a1828d5e4f7"
}
},
"licenseDetail": [
@ -40,7 +40,7 @@
"SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
],
"isOnlyProductionDependency": true,
"version": "108.0.5359.215"
"version": "102.0.5005.196"
},
{
"component": {
@ -48,12 +48,12 @@
"git": {
"name": "ffmpeg",
"repositoryUrl": "https://chromium.googlesource.com/chromium/third_party/ffmpeg",
"commitHash": "b9f01c3c54576330b2cf8918c54d5ee5be8faefe"
"commitHash": "5cd95cdf972ad92c38a4ea2d059ac9d6167302ca"
}
},
"isOnlyProductionDependency": true,
"license": "LGPL-2.1+",
"version": "5.1.git",
"version": "4.4.git",
"licenseDetail": [
" GNU LESSER GENERAL PUBLIC LICENSE",
" Version 2.1, February 1999",
@ -490,7 +490,7 @@
"other": {
"name": "H.264/AVC Video Standard",
"downloadUrl": "https://chromium.googlesource.com/chromium/third_party/ffmpeg",
"version": "5.1.git"
"version": "4.4.git"
}
},
"licenseDetail": [
@ -516,11 +516,11 @@
"git": {
"name": "nodejs",
"repositoryUrl": "https://github.com/nodejs/node",
"commitHash": "6b06e89c7dfccec6792008302af1cee57649445c"
"commitHash": "442e84a358d75152556b5d087e4dd6a51615330d"
}
},
"isOnlyProductionDependency": true,
"version": "16.17.1"
"version": "16.14.2"
},
{
"component": {
@ -528,12 +528,12 @@
"git": {
"name": "electron",
"repositoryUrl": "https://github.com/electron/electron",
"commitHash": "1df44118af1884b73f80a1087280ea694e0457dc"
"commitHash": "f887fa45dfaeeddfe20c9835ae7ca3a0823b661b"
}
},
"isOnlyProductionDependency": true,
"license": "MIT",
"version": "22.3.1"
"version": "19.1.9"
},
{
"component": {

View file

@ -30,16 +30,25 @@ async function addCell(code: string, notebook: vscode.NotebookDocument) {
const edit = vscode.NotebookEdit.insertCells(notebook.cellCount, [cell]);
const workspaceEdit = new vscode.WorkspaceEdit();
workspaceEdit.set(notebook.uri, [edit]);
const event = asPromise(vscode.workspace.onDidChangeNotebookDocument);
await vscode.workspace.applyEdit(workspaceEdit);
await event;
return notebook.cellAt(notebook.cellCount - 1);
}
async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i: number) {
async function addCellAndRun(code: string, notebook: vscode.NotebookDocument) {
const initialCellCount = notebook.cellCount;
const cell = await addCell(code, notebook);
const event = asPromise(vscode.workspace.onDidChangeNotebookDocument);
await vscode.commands.executeCommand('notebook.cell.execute', { start: i, end: i + 1 }, notebook.uri);
await event;
assert.strictEqual(cell.outputs.length, 1, 'execute failed');
await vscode.commands.executeCommand('notebook.cell.execute', { start: initialCellCount, end: initialCellCount + 1 }, notebook.uri);
try {
await event;
} catch (e) {
const result = notebook.cellAt(notebook.cellCount - 1);
assert.fail(`Notebook change event was not triggered after executing newly added cell. Initial Cell count: ${initialCellCount}. Current cell count: ${notebook.cellCount}. execution summary: ${JSON.stringify(result.executionSummary)}`);
}
assert.strictEqual(cell.outputs.length, 1, `Executed cell has no output. Initial Cell count: ${initialCellCount}. Current cell count: ${notebook.cellCount}. execution summary: ${JSON.stringify(cell.executionSummary)}`);
return cell;
}
@ -86,7 +95,7 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i:
// Run and add a bunch of cells
for (let i = 0; i < 10; i++) {
await addCellAndRun(`print ${i}`, notebookEditor.notebook, i);
await addCellAndRun(`print ${i}`, notebookEditor.notebook);
}
// Verify visible range has the last cell
@ -105,7 +114,7 @@ async function addCellAndRun(code: string, notebook: vscode.NotebookDocument, i:
assert.ok(notebookEditor);
// Verify the kernel is the secondary one
await addCellAndRun(`print`, notebookEditor.notebook, 0);
await addCellAndRun(`print`, notebookEditor.notebook);
assert.strictEqual(secondKernel.associatedNotebooks.has(notebookEditor.notebook.uri.toString()), true, `Secondary kernel was not set as the kernel for the interactive window`);

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.77.0",
"distro": "b6ce387d48144f5c7d0d33843b76e545fe561af7",
"distro": "d6eae0a132c9e3e936f4c5d5157394cf57964f0a",
"author": {
"name": "Microsoft Corporation"
},
@ -143,7 +143,7 @@
"cssnano": "^4.1.11",
"debounce": "^1.0.0",
"deemon": "^1.8.0",
"electron": "22.3.1",
"electron": "19.1.9",
"eslint": "8.7.0",
"eslint-plugin-header": "3.1.1",
"eslint-plugin-jsdoc": "^39.3.2",

View file

@ -1,4 +1,4 @@
disturl "http://nodejs.org/dist"
target "16.17.1"
target "16.14.2"
runtime "node"
build_from_source "true"

View file

@ -431,7 +431,7 @@ mimic-response@^3.1.0:
resolved "https://registry.yarnpkg.com/mimic-response/-/mimic-response-3.1.0.tgz#2d1d59af9c1b129815accc2c46a022a5ce1fa3c9"
integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6:
minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5, minimist@^1.2.6:
version "1.2.6"
resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44"
integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==
@ -442,11 +442,11 @@ mkdirp-classic@^0.5.2, mkdirp-classic@^0.5.3:
integrity sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==
mkdirp@^0.5.5:
version "0.5.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6"
integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==
version "0.5.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def"
integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==
dependencies:
minimist "^1.2.6"
minimist "^1.2.5"
ms@2.0.0:
version "2.0.0"
@ -458,6 +458,11 @@ ms@2.1.2, ms@^2.1.1:
resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
nan@^2.14.0:
version "2.15.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.15.0.tgz#3f34a473ff18e15c1b5626b62903b5ad6e665fee"
integrity sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==
nan@^2.17.0:
version "2.17.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.17.0.tgz#c0150a2368a182f033e9aa5195ec76ea41a199cb"
@ -677,13 +682,13 @@ socks@^2.3.3:
smart-buffer "^4.1.0"
spdlog@^0.13.0:
version "0.13.7"
resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.13.7.tgz#719a972be103e473770202e37dca1c9d80502180"
integrity sha512-DiWxvyHuDJKfNuanSnizY2pmqZGaSHej3xpOD4LQ+kkT3oLWpCXI6VRFDnziyXBQKCl8kmyaYnOu9QBhf1WEXQ==
version "0.13.6"
resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.13.6.tgz#26b2e13d46cbf8f2334c12ba2a8cc82de5a28f02"
integrity sha512-iGqDoA88G3Rv3lkbVQglTulp3nv12FzND6LDC7cOZ+OoFvWnXVb3+Ebhed60oZ6+IWWGwDtjXK6ympwr7C1XmQ==
dependencies:
bindings "^1.5.0"
mkdirp "^0.5.5"
nan "^2.17.0"
nan "^2.14.0"
string-width@^1.0.1:
version "1.0.2"

View file

@ -97,15 +97,22 @@ const language = getUserDefinedLocale(argvConfig);
/**
* @type {string | undefined}
**/
// Use the most preferred OS language for language recommendation.
// The API might return an empty array on Linux, such as when
// the 'C' locale is the user's only configured locale.
// No matter the OS, if the array is empty, default back to 'en'.
let osLocale = app.getPreferredSystemLanguages()?.[0] ?? 'en';
if (osLocale) {
osLocale = processZhLocale(osLocale.toLowerCase());
let osLocale = undefined;
// This if statement can be simplified once
// VS Code moves to Electron 22.
// Ref https://github.com/microsoft/vscode/issues/159813
// and https://github.com/electron/electron/pull/36035
if ('getPreferredSystemLanguages' in app
&& typeof app.getPreferredSystemLanguages === 'function') {
// Use the most preferred OS language for language recommendation.
// The API might return an empty array on Linux, such as when
// the 'C' locale is the user's only configured locale.
// No matter the OS, if the array is empty, default back to 'en'.
osLocale = app.getPreferredSystemLanguages()?.[0] ?? 'en';
if (osLocale) {
osLocale = processZhLocale(osLocale.toLowerCase());
}
}
if (language && osLocale) {
const { getNLSConfiguration } = require('./vs/base/node/languagePacks');
nlsConfigurationPromise = getNLSConfiguration(product.commit, userDataPath, metaDataFile, osLocale, language);

View file

@ -54,7 +54,7 @@
position: absolute;
top: 0;
left: 0;
z-index: 20;
z-index: 5;
pointer-events: none;
background-color: var(--separator-border);
}

View file

@ -573,6 +573,11 @@ export interface EmitterOptions {
* Optional function that's called *before* a listener is removed
*/
onWillRemoveListener?: Function;
/**
* Optional function that's called when a listener throws an error. Defaults to
* {@link onUnexpectedError}
*/
onListenerError?: (e: any) => void;
/**
* Number of listeners that are allowed before assuming a leak. Default to
* a globally configured value
@ -874,7 +879,7 @@ export class Emitter<T> {
// the driver of this
if (!this._deliveryQueue) {
this._deliveryQueue = new PrivateEventDeliveryQueue();
this._deliveryQueue = new PrivateEventDeliveryQueue(this._options?.onListenerError);
}
for (const listener of this._listeners) {
@ -899,8 +904,13 @@ export class Emitter<T> {
}
export class EventDeliveryQueue {
protected _queue = new LinkedList<EventDeliveryQueueElement>();
constructor(
private readonly _onListenerError: (e: any) => void = onUnexpectedError
) { }
get size(): number {
return this._queue.size;
}
@ -925,7 +935,7 @@ export class EventDeliveryQueue {
try {
element.listener.invoke(element.event);
} catch (e) {
onUnexpectedError(e);
this._onListenerError(e);
}
}
}

View file

@ -13,6 +13,29 @@ export interface IBuiltInExtension {
readonly metadata: any;
}
export interface IProductWalkthrough {
id: string;
steps: IProductWalkthroughStep[];
}
export interface IProductWalkthroughStep {
id: string;
title: string;
when: string;
description: string;
media:
| { type: 'image'; path: string | { hc: string; hcLight?: string; light: string; dark: string }; altText: string }
| { type: 'svg'; path: string; altText: string }
| { type: 'markdown'; path: string };
}
export interface IFeaturedExtension {
readonly id: string;
readonly title: string;
readonly description: string;
readonly imagePath: string;
}
export type ConfigurationSyncStore = {
url: string;
insidersUrl: string;
@ -50,6 +73,8 @@ export interface IProductConfiguration {
readonly dataFolderName: string; // location for extensions (e.g. ~/.vscode-insiders)
readonly builtInExtensions?: IBuiltInExtension[];
readonly walkthroughMetadata?: IProductWalkthrough[];
readonly featuredExtensions?: IFeaturedExtension[];
readonly downloadUrl?: string;
readonly updateUrl?: string;

View file

@ -3,10 +3,10 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createHash } from 'crypto';
import { Server as NetServer, Socket, createServer, createConnection } from 'net';
import { tmpdir } from 'os';
import { createDeflateRaw, ZlibOptions, InflateRaw, DeflateRaw, createInflateRaw } from 'zlib';
// import { createHash } from 'crypto';
import type { Server as NetServer, Socket } from 'net';
// import { tmpdir } from 'os';
import type * as zlib from 'zlib';
import { VSBuffer } from 'vs/base/common/buffer';
import { onUnexpectedError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
@ -17,6 +17,16 @@ import { generateUuid } from 'vs/base/common/uuid';
import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc';
import { ChunkStream, Client, ISocket, Protocol, SocketCloseEvent, SocketCloseEventType, SocketDiagnostics, SocketDiagnosticsEventType } from 'vs/base/parts/ipc/common/ipc.net';
// TODO@bpasero remove me once electron utility process has landed
function getNodeDependencies() {
return {
crypto: globalThis._VSCODE_NODE_MODULES.crypto,
zlib: globalThis._VSCODE_NODE_MODULES.zlib,
net: globalThis._VSCODE_NODE_MODULES.net,
os: globalThis._VSCODE_NODE_MODULES.os,
};
}
export class NodeSocket implements ISocket {
public readonly debugLabel: string;
@ -616,7 +626,7 @@ class ZlibInflateStream extends Disposable {
private readonly _onError = this._register(new Emitter<Error>());
public readonly onError = this._onError.event;
private readonly _zlibInflate: InflateRaw;
private readonly _zlibInflate: zlib.InflateRaw;
private readonly _recordedInflateBytes: VSBuffer[] = [];
private readonly _pendingInflateData: VSBuffer[] = [];
@ -631,10 +641,10 @@ class ZlibInflateStream extends Disposable {
private readonly _tracer: ISocketTracer,
private readonly _recordInflateBytes: boolean,
inflateBytes: VSBuffer | null,
options: ZlibOptions
options: zlib.ZlibOptions
) {
super();
this._zlibInflate = createInflateRaw(options);
this._zlibInflate = getNodeDependencies().zlib.createInflateRaw(options);
this._zlibInflate.on('error', (err) => {
this._tracer.traceSocketEvent(SocketDiagnosticsEventType.zlibInflateError, { message: err?.message, code: (<any>err)?.code });
this._onError.fire(err);
@ -676,16 +686,16 @@ class ZlibDeflateStream extends Disposable {
private readonly _onError = this._register(new Emitter<Error>());
public readonly onError = this._onError.event;
private readonly _zlibDeflate: DeflateRaw;
private readonly _zlibDeflate: zlib.DeflateRaw;
private readonly _pendingDeflateData: VSBuffer[] = [];
constructor(
private readonly _tracer: ISocketTracer,
options: ZlibOptions
options: zlib.ZlibOptions
) {
super();
this._zlibDeflate = createDeflateRaw({
this._zlibDeflate = getNodeDependencies().zlib.createDeflateRaw({
windowBits: 15
});
this._zlibDeflate.on('error', (err) => {
@ -746,7 +756,8 @@ function unmask(buffer: VSBuffer, mask: number): void {
// Read this before there's any chance it is overwritten
// Related to https://github.com/microsoft/vscode/issues/30624
export const XDG_RUNTIME_DIR = <string | undefined>process.env['XDG_RUNTIME_DIR'];
// TODO@bpasero revert me once electron utility process has landed
export const XDG_RUNTIME_DIR = typeof process !== 'undefined' ? <string | undefined>process.env['XDG_RUNTIME_DIR'] : undefined;
const safeIpcPathLengths: { [platform: number]: number } = {
[Platform.Linux]: 107,
@ -763,7 +774,7 @@ export function createRandomIPCHandle(): string {
// Mac & Unix: Use socket file
// Unix: Prefer XDG_RUNTIME_DIR over user data path
const basePath = process.platform !== 'darwin' && XDG_RUNTIME_DIR ? XDG_RUNTIME_DIR : tmpdir();
const basePath = process.platform !== 'darwin' && XDG_RUNTIME_DIR ? XDG_RUNTIME_DIR : getNodeDependencies().os.tmpdir();
const result = join(basePath, `vscode-ipc-${randomSuffix}.sock`);
// Validate length
@ -773,7 +784,7 @@ export function createRandomIPCHandle(): string {
}
export function createStaticIPCHandle(directoryPath: string, type: string, version: string): string {
const scope = createHash('md5').update(directoryPath).digest('hex');
const scope = getNodeDependencies().crypto.createHash('md5').update(directoryPath).digest('hex');
// Windows: use named pipe
if (process.platform === 'win32') {
@ -841,7 +852,7 @@ export function serve(port: number): Promise<Server>;
export function serve(namedPipe: string): Promise<Server>;
export function serve(hook: any): Promise<Server> {
return new Promise<Server>((c, e) => {
const server = createServer();
const server = getNodeDependencies().net.createServer();
server.on('error', e);
server.listen(hook, () => {
@ -856,7 +867,7 @@ export function connect(port: number, clientId: string): Promise<Client>;
export function connect(namedPipe: string, clientId: string): Promise<Client>;
export function connect(hook: any, clientId: string): Promise<Client> {
return new Promise<Client>((c, e) => {
const socket = createConnection(hook, () => {
const socket = getNodeDependencies().net.createConnection(hook, () => {
socket.removeListener('error', e);
c(Client.fromSocket(new NodeSocket(socket, `ipc-client${clientId}`), clientId));
});

View file

@ -0,0 +1,137 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
// TODO@bpasero remove me once we are on Electron 22
import type { EventEmitter } from 'events';
import * as electron from 'electron';
export declare namespace UtilityProcessProposedApi {
interface ForkOptions {
/**
* Environment key-value pairs. Default is `process.env`.
*/
env?: NodeJS.ProcessEnv;
/**
* List of string arguments passed to the executable.
*/
execArgv?: string[];
/**
* Current working directory of the child process.
*/
cwd?: string;
/**
* Allows configuring the mode for `stdout` and `stderr` of the child process.
* Default is `inherit`. String value can be one of `pipe`, `ignore`, `inherit`,
* for more details on these values you can refer to stdio documentation from
* Node.js. Currently this option only supports configuring `stdout` and `stderr`
* to either `pipe`, `inherit` or `ignore`. Configuring `stdin` is not supported;
* `stdin` will always be ignored. For example, the supported values will be
* processed as following:
*/
stdio?: (Array<'pipe' | 'ignore' | 'inherit'>) | (string);
/**
* Name of the process that will appear in `name` property of `child-process-gone`
* event of `app`. Default is `node.mojom.NodeService`.
*/
serviceName?: string;
/**
* With this flag, the utility process will be launched via the `Electron Helper
* (Plugin).app` helper executable on macOS, which can be codesigned with
* `com.apple.security.cs.disable-library-validation` and
* `com.apple.security.cs.allow-unsigned-executable-memory` entitlements. This will
* allow the utility process to load unsigned libraries. Unless you specifically
* need this capability, it is best to leave this disabled. Default is `false`.
*
* @platform darwin
*/
allowLoadingUnsignedLibraries?: boolean;
}
class UtilityProcess extends EventEmitter {
// Docs: https://electronjs.org/docs/api/utility-process
static fork(modulePath: string, args?: string[], options?: ForkOptions): UtilityProcess;
/**
* Emitted after the child process ends.
*/
on(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
once(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
addListener(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
removeListener(event: 'exit', listener: (
/**
* Contains the exit code for the process obtained from waitpid on posix, or
* GetExitCodeProcess on windows.
*/
code: number) => void): this;
/**
* Emitted when the child process sends a message using
* `process.parentPort.postMessage()`.
*/
on(event: 'message', listener: (message: any) => void): this;
once(event: 'message', listener: (message: any) => void): this;
addListener(event: 'message', listener: (message: any) => void): this;
removeListener(event: 'message', listener: (message: any) => void): this;
/**
* Emitted once the child process has spawned successfully.
*/
on(event: 'spawn', listener: Function): this;
once(event: 'spawn', listener: Function): this;
addListener(event: 'spawn', listener: Function): this;
removeListener(event: 'spawn', listener: Function): this;
/**
* Terminates the process gracefully. On POSIX, it uses SIGTERM but will ensure the
* process is reaped on exit. This function returns true if the kill is successful,
* and false otherwise.
*/
kill(): boolean;
/**
* Send a message to the child process, optionally transferring ownership of zero
* or more [`MessagePortMain`][] objects.
*
* For example:
*/
postMessage(message: any, transfer?: Electron.MessagePortMain[]): void;
/**
* A `Integer | undefined` representing the process identifier (PID) of the child
* process. If the child process fails to spawn due to errors, then the value is
* `undefined`. When the child process exits, then the value is `undefined` after
* the `exit` event is emitted.
*/
pid: (number) | (undefined);
/**
* A `NodeJS.ReadableStream | null` that represents the child process's stderr. If
* the child was spawned with options.stdio[2] set to anything other than 'pipe',
* then this will be `null`. When the child process exits, then the value is `null`
* after the `exit` event is emitted.
*/
stderr: (NodeJS.ReadableStream) | (null);
/**
* A `NodeJS.ReadableStream | null` that represents the child process's stdout. If
* the child was spawned with options.stdio[1] set to anything other than 'pipe',
* then this will be `null`. When the child process exits, then the value is `null`
* after the `exit` event is emitted.
*/
stdout: (NodeJS.ReadableStream) | (null);
}
}
export const UtilityProcess = <typeof UtilityProcessProposedApi.UtilityProcess>((electron as any).utilityProcess);
export const canUseUtilityProcess = (typeof UtilityProcess !== 'undefined');

View file

@ -395,51 +395,6 @@ suite('Async', () => {
});
suite('Limiter', () => {
test('sync', function () {
const factoryFactory = (n: number) => () => {
return Promise.resolve(n);
};
let limiter = new async.Limiter(1);
let promises: Promise<any>[] = [];
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
return Promise.all(promises).then((res) => {
assert.strictEqual(10, res.length);
limiter = new async.Limiter(100);
promises = [];
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
return Promise.all(promises).then((res) => {
assert.strictEqual(10, res.length);
});
});
});
test('async', function () {
const factoryFactory = (n: number) => () => async.timeout(0).then(() => n);
let limiter = new async.Limiter(1);
let promises: Promise<any>[] = [];
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
return Promise.all(promises).then((res) => {
assert.strictEqual(10, res.length);
limiter = new async.Limiter(100);
promises = [];
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9].forEach(n => promises.push(limiter.queue(factoryFactory(n))));
return Promise.all(promises).then((res) => {
assert.strictEqual(10, res.length);
});
});
});
test('assert degree of paralellism', function () {
let activePromises = 0;
const factoryFactory = (n: number) => () => {

View file

@ -235,6 +235,27 @@ suite('Event', function () {
}
});
test('throwingListener (custom handler)', () => {
const allError: any[] = [];
const a = new Emitter<undefined>({
onListenerError(e) { allError.push(e); }
});
let hit = false;
a.event(function () {
// eslint-disable-next-line no-throw-literal
throw 9;
});
a.event(function () {
hit = true;
});
a.fire(undefined);
assert.strictEqual(hit, true);
assert.deepStrictEqual(allError, [9]);
});
test('reusing event function and context', function () {
let counter = 0;
function listener() {

View file

@ -131,13 +131,13 @@ export class EditorWorkerService extends Disposable implements IEditorWorkerServ
return this._workerManager.withWorker().then(client => client.computeDirtyDiff(original, modified, ignoreTrimWhitespace));
}
public computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[] | null | undefined): Promise<languages.TextEdit[] | undefined> {
public computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[] | null | undefined, pretty: boolean = false): Promise<languages.TextEdit[] | undefined> {
if (isNonEmptyArray(edits)) {
if (!canSyncModel(this._modelService, resource)) {
return Promise.resolve(edits); // File too large
}
const sw = StopWatch.create(true);
const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits));
const result = this._workerManager.withWorker().then(client => client.computeMoreMinimalEdits(resource, edits, pretty));
result.finally(() => this._logService.trace('FORMAT#computeMoreMinimalEdits', resource.toString(true), sw.elapsed()));
return Promise.race([result, timeout(1000).then(() => edits)]);
@ -528,9 +528,9 @@ export class EditorWorkerClient extends Disposable implements IEditorWorkerClien
});
}
public computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[]): Promise<languages.TextEdit[]> {
public computeMoreMinimalEdits(resource: URI, edits: languages.TextEdit[], pretty: boolean): Promise<languages.TextEdit[]> {
return this._withSyncedResources([resource]).then(proxy => {
return proxy.computeMoreMinimalEdits(resource.toString(), edits);
return proxy.computeMoreMinimalEdits(resource.toString(), edits, pretty);
});
}

View file

@ -99,7 +99,7 @@ export class BlockDecorations extends ViewPart {
bottom = ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true);
} else {
top = ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, true);
bottom = decoration.range.isEmpty()
bottom = decoration.range.isEmpty() && !decoration.options.blockDoesNotCollapse
? ctx.getVerticalOffsetForLineNumber(decoration.range.startLineNumber, false)
: ctx.getVerticalOffsetAfterLineNumber(decoration.range.endLineNumber, true);
}
@ -107,7 +107,7 @@ export class BlockDecorations extends ViewPart {
const [paddingTop, paddingRight, paddingBottom, paddingLeft] = decoration.options.blockPadding ?? [0, 0, 0, 0];
block.setClassName('blockDecorations-block ' + decoration.options.blockClassName);
block.setLeft(ctx.scrollLeft + this.contentLeft - paddingLeft);
block.setLeft(this.contentLeft - paddingLeft);
block.setWidth(this.contentWidth + paddingLeft + paddingRight);
block.setTop(top - ctx.scrollTop - paddingTop);
block.setHeight(bottom - top + paddingTop + paddingBottom);

View file

@ -6,7 +6,7 @@
import * as objects from 'vs/base/common/objects';
import { ICodeEditor, IDiffEditorConstructionOptions } from 'vs/editor/browser/editorBrowser';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { ConfigurationChangedEvent, IDiffEditorOptions, IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { ICommandService } from 'vs/platform/commands/common/commands';
@ -29,6 +29,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget {
constructor(
domElement: HTMLElement,
options: IEditorOptions,
codeEditorWidgetOptions: ICodeEditorWidgetOptions,
parentEditor: ICodeEditor,
@IInstantiationService instantiationService: IInstantiationService,
@ICodeEditorService codeEditorService: ICodeEditorService,
@ -40,7 +41,7 @@ export class EmbeddedCodeEditorWidget extends CodeEditorWidget {
@ILanguageConfigurationService languageConfigurationService: ILanguageConfigurationService,
@ILanguageFeaturesService languageFeaturesService: ILanguageFeaturesService,
) {
super(domElement, { ...parentEditor.getRawOptions(), overflowWidgetsDomNode: parentEditor.getOverflowWidgetsDomNode() }, {}, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService, languageConfigurationService, languageFeaturesService);
super(domElement, { ...parentEditor.getRawOptions(), overflowWidgetsDomNode: parentEditor.getOverflowWidgetsDomNode() }, codeEditorWidgetOptions, instantiationService, codeEditorService, commandService, contextKeyService, themeService, notificationService, accessibilityService, languageConfigurationService, languageFeaturesService);
this._parentEditor = parentEditor;
this._overwriteOptions = options;

View file

@ -99,6 +99,7 @@ export interface IModelDecorationOptions {
* In this case, the range must be empty and set to the last line.
*/
blockIsAfterEnd?: boolean | null;
blockDoesNotCollapse?: boolean | null;
blockPadding?: [top: number, right: number, bottom: number, left: number] | null;
/**

View file

@ -388,7 +388,7 @@ class TwoThreeListAstNode extends ListAstNode {
}
throw new Error('Invalid child index');
}
public setChild(idx: number, node: AstNode): void {
protected setChild(idx: number, node: AstNode): void {
switch (idx) {
case 0: this._item1 = node; return;
case 1: this._item2 = node; return;
@ -506,7 +506,7 @@ class ArrayListAstNode extends ListAstNode {
getChild(idx: number): AstNode | null {
return this._children[idx];
}
setChild(idx: number, child: AstNode): void {
protected setChild(idx: number, child: AstNode): void {
this._children[idx] = child;
}
get children(): readonly AstNode[] {

View file

@ -2248,6 +2248,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
readonly description: string;
readonly blockClassName: string | null;
readonly blockIsAfterEnd: boolean | null;
readonly blockDoesNotCollapse?: boolean | null;
readonly blockPadding: [top: number, right: number, bottom: number, left: number] | null;
readonly stickiness: model.TrackedRangeStickiness;
readonly zIndex: number;
@ -2275,6 +2276,7 @@ export class ModelDecorationOptions implements model.IModelDecorationOptions {
private constructor(options: model.IModelDecorationOptions) {
this.description = options.description;
this.blockClassName = options.blockClassName ? cleanClassName(options.blockClassName) : null;
this.blockDoesNotCollapse = options.blockDoesNotCollapse ?? null;
this.blockIsAfterEnd = options.blockIsAfterEnd ?? null;
this.blockPadding = options.blockPadding ?? null;
this.stickiness = options.stickiness || model.TrackedRangeStickiness.AlwaysGrowsWhenTypingAtEdges;

View file

@ -461,7 +461,7 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable {
private static readonly _diffLimit = 100000;
public async computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[]): Promise<TextEdit[]> {
public async computeMoreMinimalEdits(modelUrl: string, edits: TextEdit[], pretty: boolean): Promise<TextEdit[]> {
const model = this._getModel(modelUrl);
if (!model) {
return edits;
@ -506,7 +506,7 @@ export class EditorSimpleWorker implements IRequestHandler, IDisposable {
}
// compute diff between original and edit.text
const changes = stringDiff(original, text, false);
const changes = stringDiff(original, text, pretty);
const editOffset = model.offsetAt(Range.lift(range).getStartPosition());
for (const change of changes) {

View file

@ -28,7 +28,7 @@ export interface IEditorWorkerService {
canComputeDirtyDiff(original: URI, modified: URI): boolean;
computeDirtyDiff(original: URI, modified: URI, ignoreTrimWhitespace: boolean): Promise<IChange[] | null>;
computeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined): Promise<TextEdit[] | undefined>;
computeMoreMinimalEdits(resource: URI, edits: TextEdit[] | null | undefined, pretty?: boolean): Promise<TextEdit[] | undefined>;
canComputeWordRanges(resource: URI): boolean;
computeWordRanges(resource: URI, range: IRange): Promise<{ [word: string]: IRange[] } | null>;

View file

@ -92,7 +92,7 @@ export abstract class SymbolNavigationAction extends EditorAction2 {
}
}
}
return result;
return <typeof opts>result;
}
readonly configuration: SymbolNavigationActionConfig;

View file

@ -313,7 +313,7 @@ export class ReferenceWidget extends peekView.PeekViewWidget {
enabled: false
}
};
this._preview = this._instantiationService.createInstance(EmbeddedCodeEditorWidget, this._previewContainer, options, this.editor);
this._preview = this._instantiationService.createInstance(EmbeddedCodeEditorWidget, this._previewContainer, options, {}, this.editor);
dom.hide(this._previewContainer);
this._previewNotAvailableMessage = new TextModel(nls.localize('missingPreviewMessage', "no preview available"), PLAINTEXT_LANGUAGE_ID, TextModel.DEFAULT_CREATION_OPTIONS, null, this._undoRedoService, this._languageService, this._languageConfigurationService);

View file

@ -710,7 +710,7 @@ export class SynchronizedInlineCompletionsCache extends Disposable {
for (const c of this.completions) {
const newRange = model.getDecorationRange(c.decorationId);
if (!newRange) {
onUnexpectedError(new Error('Decoration has no range'));
// onUnexpectedError(new Error('Decoration has no range'));
continue;
}
if (!c.synchronizedRange.equalsRange(newRange)) {

View file

@ -0,0 +1,30 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { registerAction2 } from 'vs/platform/actions/common/actions';
import { EditorContributionInstantiation, registerEditorContribution } from 'vs/editor/browser/editorExtensions';
import { InteractiveEditorController } from 'vs/editor/contrib/interactive/browser/interactiveEditorWidget';
import * as interactiveEditorActions from 'vs/editor/contrib/interactive/browser/interactiveEditorActions';
import { IInteractiveEditorService } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { InteractiveEditorServiceImpl } from 'vs/editor/contrib/interactive/common/interactiveEditorServiceImpl';
registerSingleton(IInteractiveEditorService, InteractiveEditorServiceImpl, InstantiationType.Delayed);
registerEditorContribution(InteractiveEditorController.ID, InteractiveEditorController, EditorContributionInstantiation.Lazy);
registerAction2(interactiveEditorActions.StartSessionAction);
registerAction2(interactiveEditorActions.ToggleHistory);
registerAction2(interactiveEditorActions.MakeRequestAction);
registerAction2(interactiveEditorActions.StopRequestAction);
registerAction2(interactiveEditorActions.AcceptWithPreviewInteractiveEditorAction);
registerAction2(interactiveEditorActions.TogglePreviewMode);
registerAction2(interactiveEditorActions.CancelSessionAction);
registerAction2(interactiveEditorActions.ArrowOutUpAction);
registerAction2(interactiveEditorActions.ArrowOutDownAction);
registerAction2(interactiveEditorActions.FocusInteractiveEditor);
registerAction2(interactiveEditorActions.PreviousFromHistory);
registerAction2(interactiveEditorActions.NextFromHistory);
registerAction2(interactiveEditorActions.UndoCommand);

View file

@ -0,0 +1,124 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.monaco-editor .interactive-editor {
z-index: 100;
color: inherit;
padding: 6px 0 6px 6px;
}
/* body */
.monaco-editor .interactive-editor .body {
display: flex;
}
.monaco-editor .interactive-editor .body .expando {
flex-grow: 0;
padding-top: 6px;
padding-right: 2px;
cursor: pointer;
}
.monaco-editor .interactive-editor .body .history {
display: block;
margin: 0;
color: var(--vscode-descriptionForeground);
list-style-type: disc;
line-height: 20px;
}
.monaco-editor .interactive-editor .body .history:not(:empty) {
margin: 0;
padding: 4px 0 0 12px;
}
.monaco-editor .interactive-editor .body .history.hidden {
display: none;
}
.monaco-editor .interactive-editor .body.preview {
padding: 4px 4px 0 4px;
}
.monaco-editor .interactive-editor .body .content .input {
border-radius: 2px;
box-sizing: border-box;
padding: 2px;
background-color: var(--vscode-input-background);
border: 1px solid var(--vscode-settings-textInputBorder);
cursor: text;
}
.monaco-editor .interactive-editor .monaco-editor-background {
background-color: var(--vscode-input-background);
}
.monaco-editor .interactive-editor .body .content .input.synthetic-focus {
outline: 1px solid var(--vscode-focusBorder);
}
.monaco-editor .interactive-editor .body .content .input .editor-placeholder {
position: absolute;
z-index: 1;
padding: 3px 0 0 2px;
color: var(--vscode-input-placeholderForeground);
font-family: var(--monaco-monospace-font);
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.monaco-editor .interactive-editor .body .content .input .editor-placeholder.hidden {
display: none;
}
.monaco-editor .interactive-editor .body .content .input .editor-container {
/* height: 24px; */
vertical-align: middle;
}
.monaco-editor .interactive-editor .body .toolbar {
display: flex;
flex-direction: column;
align-self: start;
padding: 4px 8px 0 2px;
}
.monaco-editor .interactive-editor .body .toolbar .actions-container {
display: flex;
flex-direction: row;
gap: 4px;
}
/* progress bit */
.monaco-editor .interactive-editor .progress {
position: relative;
width: calc(100% - 18px);
left: 19px;
}
/* UGLY - fighting against workbench styles */
.monaco-workbench .part.editor > .content .monaco-editor .interactive-editor .progress .monaco-progress-container {
top: 0;
}
/* decoration styles */
.monaco-editor .interactive-editor-lines-deleted-range-inline {
text-decoration: line-through;
background-color: var(--vscode-diffEditor-removedTextBackground);
opacity: 0.6;
}
.monaco-editor .interactive-editor-lines-inserted-range {
background-color: var(--vscode-diffEditor-insertedTextBackground);
}
.monaco-editor .interactive-editor-block {
border-radius: 4px;
border: 1px solid var(--vscode-widget-border);
box-shadow: 0 0 8px 1px var(--vscode-widget-shadow);
}

View file

@ -0,0 +1,328 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Codicon } from 'vs/base/common/codicons';
import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction2 } from 'vs/editor/browser/editorExtensions';
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { EditorContextKeys } from 'vs/editor/common/editorContextKeys';
import { InteractiveEditorController } from 'vs/editor/contrib/interactive/browser/interactiveEditorWidget';
import { CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_PREVIEW, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, MENU_INTERACTIVE_EDITOR_WIDGET_LHS, CTX_INTERACTIVE_EDITOR_HISTORY_VISIBLE } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { localize } from 'vs/nls';
import { IAction2Options } from 'vs/platform/actions/common/actions';
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
export class StartSessionAction extends EditorAction2 {
constructor() {
super({
id: 'interactiveEditor.start',
title: { value: localize('run', 'Start Session'), original: 'Start Session' },
category: AbstractInteractiveEditorAction.category,
f1: true,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, EditorContextKeys.writable, CTX_INTERACTIVE_EDITOR_VISIBLE.negate()),
keybinding: {
weight: KeybindingWeight.WorkbenchContrib,
primary: KeyChord(KeyMod.CtrlCmd | KeyCode.KeyK, KeyCode.KeyI)
}
});
}
override runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) {
InteractiveEditorController.get(editor)?.run();
}
}
abstract class AbstractInteractiveEditorAction extends EditorAction2 {
static readonly category = { value: localize('cat', 'Interactive Editor'), original: 'Interactive Editor' };
constructor(desc: IAction2Options) {
super({
...desc,
category: AbstractInteractiveEditorAction.category,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_HAS_PROVIDER, desc.precondition)
});
}
override runEditorCommand(accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) {
if (editor instanceof EmbeddedCodeEditorWidget) {
editor = editor.getParentEditor();
}
const ctrl = InteractiveEditorController.get(editor);
if (!ctrl) {
return;
}
this.runInteractiveEditorCommand(accessor, ctrl, editor, ..._args);
}
abstract runInteractiveEditorCommand(accessor: ServicesAccessor, ctrl: InteractiveEditorController, editor: ICodeEditor, ...args: any[]): void;
}
export class MakeRequestAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.accept',
title: localize('accept', 'Make Request'),
icon: Codicon.arrowUp,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_EMPTY.negate()),
keybinding: {
when: CTX_INTERACTIVE_EDITOR_FOCUSED,
weight: KeybindingWeight.EditorCore + 7,
primary: KeyCode.Enter
},
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET,
group: 'main',
order: 1,
when: CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST.isEqualTo(false)
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.accept();
}
}
export class StopRequestAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.stop',
title: localize('stop', 'Stop Request'),
icon: Codicon.debugStop,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_EMPTY.negate(), CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST),
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET,
group: 'main',
order: 1,
when: CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST
},
keybinding: {
weight: KeybindingWeight.EditorContrib,
primary: KeyCode.Escape
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.cancelCurrentRequest();
}
}
export class AcceptWithPreviewInteractiveEditorAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.acceptWithPreview',
title: localize('acceptPreview', 'Ask Question & Preview Reply'),
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_EMPTY.negate()),
keybinding: {
when: CTX_INTERACTIVE_EDITOR_FOCUSED,
weight: KeybindingWeight.EditorCore + 7,
primary: KeyMod.Shift + KeyCode.Enter
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.accept(true);
}
}
export class TogglePreviewMode extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.togglePreview',
title: localize('togglePreview', 'Inline Preview'),
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE),
toggled: CTX_INTERACTIVE_EDITOR_PREVIEW,
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET,
group: 'C',
order: 1
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.togglePreview();
}
}
export class CancelSessionAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.cancel',
title: localize('cancel', 'Cancel'),
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
keybinding: {
weight: KeybindingWeight.EditorContrib - 1,
primary: KeyCode.Escape
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.cancelSession();
}
}
export class ArrowOutUpAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.arrowOutUp',
title: localize('arrowUp', 'Cursor Up'),
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST),
keybinding: {
weight: KeybindingWeight.EditorCore,
primary: KeyCode.UpArrow
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.arrowOut(true);
}
}
export class ArrowOutDownAction extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.arrowOutDown',
title: localize('arrowDown', 'Cursor Down'),
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST),
keybinding: {
weight: KeybindingWeight.EditorCore,
primary: KeyCode.DownArrow
}
});
}
runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.arrowOut(false);
}
}
export class FocusInteractiveEditor extends EditorAction2 {
constructor() {
super({
id: 'interactiveEditor.focus',
title: localize('focus', 'Focus'),
category: AbstractInteractiveEditorAction.category,
precondition: ContextKeyExpr.and(EditorContextKeys.editorTextFocus, CTX_INTERACTIVE_EDITOR_VISIBLE, CTX_INTERACTIVE_EDITOR_FOCUSED.negate()),
keybinding: [{
weight: KeybindingWeight.EditorCore + 10, // win against core_command
when: CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION.isEqualTo('above'),
primary: KeyCode.DownArrow,
}, {
weight: KeybindingWeight.EditorCore + 10, // win against core_command
when: CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION.isEqualTo('below'),
primary: KeyCode.UpArrow,
}]
});
}
override runEditorCommand(_accessor: ServicesAccessor, editor: ICodeEditor, ..._args: any[]) {
InteractiveEditorController.get(editor)?.focus();
}
}
export class PreviousFromHistory extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.previousFromHistory',
title: localize('previousFromHistory', 'Previous From History'),
precondition: CTX_INTERACTIVE_EDITOR_FOCUSED,
keybinding: {
weight: KeybindingWeight.EditorCore + 10, // win against core_command
primary: KeyMod.CtrlCmd | KeyCode.UpArrow,
}
});
}
override runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.populateHistory(true);
}
}
export class NextFromHistory extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.nextFromHistory',
title: localize('nextFromHistory', 'Next From History'),
precondition: CTX_INTERACTIVE_EDITOR_FOCUSED,
keybinding: {
weight: KeybindingWeight.EditorCore + 10, // win against core_command
primary: KeyMod.CtrlCmd | KeyCode.DownArrow,
}
});
}
override runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.populateHistory(false);
}
}
export class UndoCommand extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.undo',
title: localize('undo', 'Undo'),
icon: Codicon.commentDiscussion,
precondition: ContextKeyExpr.and(CTX_INTERACTIVE_EDITOR_VISIBLE),
keybinding: {
weight: KeybindingWeight.EditorContrib + 10,
primary: KeyMod.CtrlCmd | KeyCode.KeyZ,
},
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET,
group: 'B',
order: 1
}
});
}
override runInteractiveEditorCommand(_accessor: ServicesAccessor, _ctrl: InteractiveEditorController, editor: ICodeEditor, ..._args: any[]): void {
editor.getModel()?.undo();
}
}
export class ToggleHistory extends AbstractInteractiveEditorAction {
constructor() {
super({
id: 'interactiveEditor.toggleHistory',
title: localize('toggleHistory', 'Toggle History'),
icon: Codicon.chevronRight,
precondition: CTX_INTERACTIVE_EDITOR_VISIBLE,
toggled: {
condition: CTX_INTERACTIVE_EDITOR_HISTORY_VISIBLE,
icon: Codicon.chevronDown,
},
menu: {
id: MENU_INTERACTIVE_EDITOR_WIDGET_LHS,
group: 'main',
order: 1
}
});
}
override runInteractiveEditorCommand(_accessor: ServicesAccessor, ctrl: InteractiveEditorController, _editor: ICodeEditor, ..._args: any[]): void {
ctrl.toggleHistory();
}
}

View file

@ -0,0 +1,744 @@
/*---------------------------------------------------------------------------------------------
* 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!./interactiveEditor';
import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation';
import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle';
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorLayoutInfo, EditorOption } from 'vs/editor/common/config/editorOptions';
import { IRange, Range } from 'vs/editor/common/core/range';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { localize } from 'vs/nls';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ZoneWidget } from 'vs/editor/contrib/zoneWidget/browser/zoneWidget';
import { assertType } from 'vs/base/common/types';
import { IInteractiveEditorResponse, IInteractiveEditorService, CTX_INTERACTIVE_EDITOR_FOCUSED, CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST, CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST, CTX_INTERACTIVE_EDITOR_EMPTY, CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION, CTX_INTERACTIVE_EDITOR_PREVIEW, CTX_INTERACTIVE_EDITOR_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET, CTX_INTERACTIVE_EDITOR_HISTORY_VISIBLE, MENU_INTERACTIVE_EDITOR_WIDGET_LHS } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { EditOperation } from 'vs/editor/common/core/editOperation';
import { Iterable } from 'vs/base/common/iterator';
import { IModelDeltaDecoration, ITextModel, IValidEditOperation } from 'vs/editor/common/model';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { Dimension, addDisposableListener, getTotalHeight, getTotalWidth, h, reset } from 'vs/base/browser/dom';
import { Emitter, Event } from 'vs/base/common/event';
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
import { EditorExtensionsRegistry } from 'vs/editor/browser/editorExtensions';
import { SnippetController2 } from 'vs/editor/contrib/snippet/browser/snippetController2';
import { IModelService } from 'vs/editor/common/services/model';
import { URI } from 'vs/base/common/uri';
import { EmbeddedCodeEditorWidget } from 'vs/editor/browser/widget/embeddedCodeEditorWidget';
import { GhostTextController } from 'vs/editor/contrib/inlineCompletions/browser/ghostTextController';
import { MenuWorkbenchToolBar } from 'vs/platform/actions/browser/toolbar';
import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar';
import { SuggestController } from 'vs/editor/contrib/suggest/browser/suggestController';
import { Position } from 'vs/editor/common/core/position';
import { Selection } from 'vs/editor/common/core/selection';
import { raceCancellationError } from 'vs/base/common/async';
import { isCancellationError } from 'vs/base/common/errors';
import { IEditorWorkerService } from 'vs/editor/common/services/editorWorker';
import { ILogService } from 'vs/platform/log/common/log';
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
import { StopWatch } from 'vs/base/common/stopwatch';
class InteractiveEditorWidget {
private static _noop = () => { };
private readonly _elements = h(
'div.interactive-editor@root',
[
h('div.body', [
h('div.toolbar@lhsToolbar'),
h('div.content', [
h('div.input@input', [
h('div.editor-placeholder@placeholder'),
h('div.editor-container@editor'),
]),
h('ol.history.hidden@history'),
]),
h('div.toolbar@rhsToolbar'),
]),
h('div.progress@progress')
]
);
private readonly _store = new DisposableStore();
private readonly _inputEditor: ICodeEditor;
private readonly _inputModel: ITextModel;
private readonly _ctxInputEmpty: IContextKey<boolean>;
private readonly _ctxHistoryVisible: IContextKey<boolean>;
private readonly _progressBar: ProgressBar;
private readonly _onDidChangeHeight = new Emitter<void>();
readonly onDidChangeHeight: Event<void> = this._onDidChangeHeight.event;
private _isExpanded = false;
private _editorDim: Dimension | undefined;
public acceptInput: (preview: boolean) => void = InteractiveEditorWidget._noop;
private _cancelInput: () => void = InteractiveEditorWidget._noop;
constructor(
parentEditor: ICodeEditor | undefined,
@IModelService private readonly _modelService: IModelService,
@IContextKeyService private readonly _contextKeyService: IContextKeyService,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
) {
this._ctxHistoryVisible = CTX_INTERACTIVE_EDITOR_HISTORY_VISIBLE.bindTo(this._contextKeyService);
// editor logic
const editorOptions: IEditorConstructionOptions = {
ariaLabel: localize('aria-label', "Interactive Editor Input"),
wordWrap: 'on',
overviewRulerLanes: 0,
glyphMargin: false,
lineNumbers: 'off',
folding: false,
selectOnLineNumbers: false,
hideCursorInOverviewRuler: true,
selectionHighlight: false,
scrollbar: {
useShadows: false,
vertical: 'hidden',
horizontal: 'auto',
// alwaysConsumeMouseWheel: false
},
lineDecorationsWidth: 0,
overviewRulerBorder: false,
scrollBeyondLastLine: false,
renderLineHighlight: 'none',
fixedOverflowWidgets: true,
dragAndDrop: false,
revealHorizontalRightPadding: 5,
minimap: { enabled: false },
guides: { indentation: false },
cursorWidth: 2,
wrappingStrategy: 'advanced',
wrappingIndent: 'none',
padding: { top: 3, bottom: 2 },
renderWhitespace: 'none',
dropIntoEditor: { enabled: true },
quickSuggestions: false,
suggest: {
showIcons: false,
showSnippets: false,
}
};
const codeEditorWidgetOptions: ICodeEditorWidgetOptions = {
isSimpleWidget: true,
contributions: EditorExtensionsRegistry.getSomeEditorContributions([
SnippetController2.ID,
GhostTextController.ID,
SuggestController.ID
])
};
this._inputEditor = parentEditor
? this._instantiationService.createInstance(EmbeddedCodeEditorWidget, this._elements.editor, editorOptions, codeEditorWidgetOptions, parentEditor)
: this._instantiationService.createInstance(CodeEditorWidget, this._elements.editor, editorOptions, codeEditorWidgetOptions);
this._store.add(this._inputEditor);
const uri = URI.from({ scheme: 'vscode', authority: 'interactive-editor', path: `/interactive-editor/model.txt` });
this._inputModel = this._modelService.getModel(uri) ?? this._modelService.createModel('', null, uri);
this._inputEditor.setModel(this._inputModel);
// show/hide placeholder depending on text model being empty
// content height
const currentContentHeight = 0;
this._ctxInputEmpty = CTX_INTERACTIVE_EDITOR_EMPTY.bindTo(this._contextKeyService);
const togglePlaceholder = () => {
const hasText = this._inputModel.getValueLength() > 0;
this._elements.placeholder.classList.toggle('hidden', hasText);
this._ctxInputEmpty.set(!hasText);
const contentHeight = this._inputEditor.getContentHeight();
if (contentHeight !== currentContentHeight && this._editorDim) {
this._editorDim = this._editorDim.with(undefined, contentHeight);
this._inputEditor.layout(this._editorDim);
this._onDidChangeHeight.fire();
}
};
this._store.add(this._inputModel.onDidChangeContent(togglePlaceholder));
togglePlaceholder();
this._store.add(addDisposableListener(this._elements.placeholder, 'click', () => this._inputEditor.focus()));
const lhsToolbar = this._instantiationService.createInstance(MenuWorkbenchToolBar, this._elements.lhsToolbar, MENU_INTERACTIVE_EDITOR_WIDGET_LHS, {
telemetrySource: 'interactiveEditorWidget-toolbar-lhs',
toolbarOptions: { primaryGroup: 'main' }
});
this._store.add(lhsToolbar);
const rhsToolbar = this._instantiationService.createInstance(MenuWorkbenchToolBar, this._elements.rhsToolbar, MENU_INTERACTIVE_EDITOR_WIDGET, {
telemetrySource: 'interactiveEditorWidget-toolbar-rhs',
toolbarOptions: { primaryGroup: 'main' }
});
this._store.add(rhsToolbar);
this._progressBar = new ProgressBar(this._elements.progress);
this._store.add(this._progressBar);
}
dispose(): void {
this._store.dispose();
this._ctxInputEmpty.reset();
this._ctxHistoryVisible.reset();
}
getDomNode(): HTMLElement {
return this._elements.root;
}
layout(dim: Dimension) {
const innerEditorWidth = Math.min(
Number.MAX_SAFE_INTEGER, // TODO@jrieken define max width?
dim.width - (getTotalWidth(this._elements.lhsToolbar) + getTotalWidth(this._elements.rhsToolbar) + 12 /* L/R-padding */)
);
const newDim = new Dimension(innerEditorWidth, this._inputEditor.getContentHeight());
if (!this._editorDim || !Dimension.equals(this._editorDim, newDim)) {
this._editorDim = newDim;
this._inputEditor.layout(this._editorDim);
this._elements.placeholder.style.width = `${innerEditorWidth - 4 /* input-padding*/}px`;
}
}
getHeight(): number {
return this._inputEditor.getContentHeight() + getTotalHeight(this._elements.history);
}
updateProgress(show: boolean) {
if (show) {
this._progressBar.infinite();
} else {
this._progressBar.stop();
}
}
getInput(placeholder: string, value: string, token: CancellationToken): Promise<{ value: string; preview: boolean } | undefined> {
this._elements.placeholder.innerText = placeholder;
this._elements.placeholder.style.fontSize = `${this._inputEditor.getOption(EditorOption.fontSize)}px`;
this._elements.placeholder.style.lineHeight = `${this._inputEditor.getOption(EditorOption.lineHeight)}px`;
this._inputModel.setValue(value);
const disposeOnDone = new DisposableStore();
disposeOnDone.add(this._inputEditor.onDidLayoutChange(() => this._onDidChangeHeight.fire()));
const ctxInnerCursorFirst = CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST.bindTo(this._contextKeyService);
const ctxInnerCursorLast = CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST.bindTo(this._contextKeyService);
const ctxInputEditorFocused = CTX_INTERACTIVE_EDITOR_FOCUSED.bindTo(this._contextKeyService);
return new Promise<{ value: string; preview: boolean } | undefined>(resolve => {
this._cancelInput = () => {
this.acceptInput = InteractiveEditorWidget._noop;
this._cancelInput = InteractiveEditorWidget._noop;
resolve(undefined);
return true;
};
this.acceptInput = (preview) => {
const newValue = this._inputEditor.getModel()!.getValue();
if (newValue.trim().length === 0) {
// empty or whitespace only
this._cancelInput();
return;
}
this.acceptInput = InteractiveEditorWidget._noop;
this._cancelInput = InteractiveEditorWidget._noop;
resolve({ value: newValue, preview });
const entry = document.createElement('li');
entry.classList.add('history-entry');
entry.innerText = newValue;
this._elements.history.insertBefore(entry, this._elements.history.firstChild);
this._onDidChangeHeight.fire();
};
disposeOnDone.add(token.onCancellationRequested(() => this._cancelInput()));
// CONTEXT KEYS
// (1) inner cursor position (last/first line selected)
const updateInnerCursorFirstLast = () => {
if (!this._inputEditor.hasModel()) {
return;
}
const { lineNumber } = this._inputEditor.getPosition();
ctxInnerCursorFirst.set(lineNumber === 1);
ctxInnerCursorLast.set(lineNumber === this._inputEditor.getModel().getLineCount());
};
disposeOnDone.add(this._inputEditor.onDidChangeCursorPosition(updateInnerCursorFirstLast));
updateInnerCursorFirstLast();
// (2) input editor focused or not
const updateFocused = () => {
const hasFocus = this._inputEditor.hasWidgetFocus();
ctxInputEditorFocused.set(hasFocus);
this._elements.input.classList.toggle('synthetic-focus', hasFocus);
};
disposeOnDone.add(this._inputEditor.onDidFocusEditorWidget(updateFocused));
disposeOnDone.add(this._inputEditor.onDidBlurEditorWidget(updateFocused));
updateFocused();
this.focus();
}).finally(() => {
disposeOnDone.dispose();
ctxInnerCursorFirst.reset();
ctxInnerCursorLast.reset();
ctxInputEditorFocused.reset();
});
}
populateInputField(value: string) {
this._inputModel.setValue(value.trim());
this._inputEditor.setSelection(this._inputModel.getFullModelRange());
}
toggleHistory(): void {
this._isExpanded = !this._isExpanded;
this._elements.history.classList.toggle('hidden', !this._isExpanded);
this._ctxHistoryVisible.set(this._isExpanded);
this._onDidChangeHeight.fire();
}
reset() {
this._ctxInputEmpty.reset();
// empty history
this._isExpanded = false;
this._elements.history.classList.toggle('hidden', true);
this._ctxHistoryVisible.reset();
reset(this._elements.history);
}
focus() {
this._inputEditor.focus();
}
}
export class InteractiveEditorZoneWidget extends ZoneWidget {
readonly widget: InteractiveEditorWidget;
private readonly _ctxVisible: IContextKey<boolean>;
private readonly _ctxCursorPosition: IContextKey<'above' | 'below' | ''>;
constructor(
editor: ICodeEditor,
@IInstantiationService private readonly _instaService: IInstantiationService,
@IContextKeyService contextKeyService: IContextKeyService,
) {
super(editor, { showFrame: false, showArrow: false, isAccessible: true, className: 'interactive-editor-widget', keepEditorSelection: true });
this._ctxVisible = CTX_INTERACTIVE_EDITOR_VISIBLE.bindTo(contextKeyService);
this._ctxCursorPosition = CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION.bindTo(contextKeyService);
this._disposables.add(toDisposable(() => {
this._ctxVisible.reset();
this._ctxCursorPosition.reset();
}));
this.widget = this._instaService.createInstance(InteractiveEditorWidget, this.editor);
this._disposables.add(this.widget.onDidChangeHeight(() => this._relayout()));
this._disposables.add(this.widget);
this.create();
// todo@jrieken listen ONLY when showing
const updateCursorIsAboveContextKey = () => {
if (!this.position || !this.editor.hasModel()) {
this._ctxCursorPosition.reset();
} else if (this.position.lineNumber === this.editor.getPosition().lineNumber) {
this._ctxCursorPosition.set('above');
} else if (this.position.lineNumber + 1 === this.editor.getPosition().lineNumber) {
this._ctxCursorPosition.set('below');
} else {
this._ctxCursorPosition.reset();
}
};
this._disposables.add(this.editor.onDidChangeCursorPosition(e => updateCursorIsAboveContextKey()));
this._disposables.add(this.editor.onDidFocusEditorText(e => updateCursorIsAboveContextKey()));
updateCursorIsAboveContextKey();
}
protected override _fillContainer(container: HTMLElement): void {
container.appendChild(this.widget.getDomNode());
}
protected override _getWidth(info: EditorLayoutInfo): number {
// TODO@jrieken
// makes the zone widget wider than wanted but this aligns
// it with wholeLine decorations that are added above
return info.width;
}
private _dimension?: Dimension;
protected override _onWidth(widthInPixel: number): void {
if (this._dimension) {
this._doLayout(this._dimension.height, widthInPixel);
}
}
protected override _doLayout(heightInPixel: number, widthInPixel: number): void {
const info = this.editor.getLayoutInfo();
const spaceLeft = info.lineNumbersWidth + info.glyphMarginWidth + info.decorationsWidth;
const spaceRight = info.minimap.minimapWidth + info.verticalScrollbarWidth;
const width = widthInPixel - (spaceLeft + spaceRight);
this._dimension = new Dimension(width, heightInPixel);
this.widget.getDomNode().style.marginLeft = `${spaceLeft}px`;
this.widget.getDomNode().style.marginRight = `${spaceRight}px`;
this.widget.layout(this._dimension);
}
private _computeHeightInLines(): number {
const lineHeight = this.editor.getOption(EditorOption.lineHeight);
const contentHeightInLines = (this.widget.getHeight() / lineHeight);
return 2 + contentHeightInLines;
}
protected override _relayout() {
super._relayout(this._computeHeightInLines());
}
async getInput(where: IRange, placeholder: string, value: string, token: CancellationToken): Promise<{ value: string; preview: boolean } | undefined> {
assertType(this.editor.hasModel());
super.show(where, this._computeHeightInLines());
this._ctxVisible.set(true);
const task = this.widget.getInput(placeholder, value, token);
const result = await task;
return result;
}
override hide(): void {
this._ctxVisible.reset();
this._ctxCursorPosition.reset();
this.widget.reset();
super.hide();
}
}
export class InteractiveEditorController implements IEditorContribution {
static ID = 'interactiveEditor';
static get(editor: ICodeEditor) {
return editor.getContribution<InteractiveEditorController>(InteractiveEditorController.ID);
}
private static _decoBlock = ModelDecorationOptions.register({
description: 'interactive-editor',
blockClassName: 'interactive-editor-block',
blockDoesNotCollapse: true,
blockPadding: [1, 0, 1, 4]
});
private static _promptHistory: string[] = [];
private _historyOffset: number = -1;
private readonly _store = new DisposableStore();
private readonly _zone: InteractiveEditorZoneWidget;
private readonly _ctxShowPreview: IContextKey<boolean>;
private readonly _ctxHasActiveRequest: IContextKey<boolean>;
private _ctsSession: CancellationTokenSource = new CancellationTokenSource();
private _ctsRequest?: CancellationTokenSource;
constructor(
private readonly _editor: ICodeEditor,
@IInstantiationService instaService: IInstantiationService,
@IContextKeyService contextKeyService: IContextKeyService,
@IInteractiveEditorService private readonly _interactiveEditorService: IInteractiveEditorService,
@IEditorWorkerService private readonly _editorWorkerService: IEditorWorkerService,
@ILogService private readonly _logService: ILogService,
) {
this._zone = this._store.add(instaService.createInstance(InteractiveEditorZoneWidget, this._editor));
this._ctxShowPreview = CTX_INTERACTIVE_EDITOR_PREVIEW.bindTo(contextKeyService);
this._ctxHasActiveRequest = CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST.bindTo(contextKeyService);
}
dispose(): void {
this._store.dispose();
this._ctsSession.dispose(true);
this._ctsSession.dispose();
}
getId(): string {
return InteractiveEditorController.ID;
}
async run(): Promise<void> {
this._ctsSession.dispose(true);
if (!this._editor.hasModel()) {
return;
}
const provider = Iterable.first(this._interactiveEditorService.getAll());
if (!provider) {
this._logService.trace('[IE] NO provider found');
return;
}
this._ctsSession = new CancellationTokenSource();
const session = await provider.prepareInteractiveEditorSession(this._editor.getModel(), this._editor.getSelection(), this._ctsSession.token);
if (!session) {
this._logService.trace('[IE] NO session', provider.debugName);
return;
}
this._logService.trace('[IE] NEW session', provider.debugName);
const decoBackground = this._editor.createDecorationsCollection();
const decoPreview = this._editor.createDecorationsCollection();
const decoWholeRange = this._editor.createDecorationsCollection();
decoWholeRange.set([{
range: this._editor.getSelection(),
options: { description: 'interactive-editor-marker' }
}]);
let placeholder = session.placeholder ?? '';
let value = '';
const listener = new DisposableStore();
this._editor.onDidChangeModel(this._ctsSession.cancel, this._ctsSession, listener);
// CANCEL if the document has changed outside the current range
this._editor.onDidChangeModelContent(e => {
let cancel = false;
const wholeRange = decoWholeRange.getRange(0);
if (!wholeRange) {
cancel = true;
} else {
for (const change of e.changes) {
if (!Range.areIntersectingOrTouching(wholeRange, change.range)) {
cancel = true;
break;
}
}
}
if (cancel) {
this._ctsSession.cancel();
this._logService.trace('[IE] CANCEL because of model change OUTSIDE range');
}
}, undefined, listener);
do {
const wholeRange = decoWholeRange.getRange(0);
if (!wholeRange) {
// nuked whole file contents?
break;
}
const newDecorations: IModelDeltaDecoration[] = [{
range: wholeRange,
options: InteractiveEditorController._decoBlock
}];
decoBackground.set(newDecorations);
this._historyOffset = -1;
const input = await this._zone.getInput(wholeRange.collapseToEnd(), placeholder, value, this._ctsSession.token);
if (!input || !input.value) {
continue;
}
this._ctsRequest?.dispose(true);
this._ctsRequest = new CancellationTokenSource(this._ctsSession.token);
const sw = StopWatch.create();
const task = provider.provideResponse(
session,
{
session,
prompt: input.value,
selection: this._editor.getSelection(),
wholeRange: wholeRange
},
this._ctsRequest.token
);
let reply: IInteractiveEditorResponse | null | undefined;
try {
this._zone.widget.updateProgress(true);
this._ctxHasActiveRequest.set(true);
reply = await raceCancellationError(Promise.resolve(task), this._ctsRequest.token);
} catch (e) {
if (!isCancellationError(e)) {
this._logService.error('[IE] ERROR during request', provider.debugName);
this._logService.error(e);
}
} finally {
this._ctxHasActiveRequest.set(false);
this._zone.widget.updateProgress(false);
}
this._logService.trace('[IE] request took', sw.elapsed(), provider.debugName);
if (this._ctsRequest.token.isCancellationRequested) {
value = input.value;
continue;
}
if (!reply || isFalsyOrEmpty(reply.edits)) {
this._logService.trace('[IE] NO reply or edits', provider.debugName);
reply = { edits: [] };
placeholder = '';
continue;
}
// make edits more minimal
const moreMinimalEdits = (await this._editorWorkerService.computeMoreMinimalEdits(this._editor.getModel().uri, reply.edits, true)) ?? reply.edits;
// clear old preview
decoPreview.clear();
const undoEdits: IValidEditOperation[] = [];
this._editor.pushUndoStop();
this._editor.executeEdits(
'interactive-editor',
moreMinimalEdits.map(edit => {
// return EditOperation.replaceMove(Range.lift(edit.range), edit.text); ???
return EditOperation.replace(Range.lift(edit.range), edit.text);
}),
_undoEdits => {
let last: Position | null = null;
for (const undoEdit of _undoEdits) {
undoEdits.push(undoEdit);
last = !last || last.isBefore(undoEdit.range.getEndPosition()) ? undoEdit.range.getEndPosition() : last;
}
return last && [Selection.fromPositions(last)];
}
);
this._editor.pushUndoStop();
if (input.preview) {
const decorations: IModelDeltaDecoration[] = [];
for (const edit of undoEdits) {
let content = edit.text;
if (content.length > 12) {
content = content.substring(0, 12) + '…';
}
decorations.push({
range: edit.range,
options: {
description: 'interactive-editor-inline-diff',
className: 'interactive-editor-lines-inserted-range',
before: {
content,
inlineClassName: 'interactive-editor-lines-deleted-range-inline',
attachedData: edit
}
}
});
}
decoPreview.set(decorations);
}
if (!InteractiveEditorController._promptHistory.includes(input.value)) {
InteractiveEditorController._promptHistory.unshift(input.value);
}
placeholder = reply.placeholder ?? session.placeholder ?? '';
} while (!this._ctsSession.token.isCancellationRequested);
// done, cleanup
decoWholeRange.clear();
decoBackground.clear();
decoPreview.clear();
listener.dispose();
session.dispose?.();
this._zone.hide();
this._editor.focus();
this._logService.trace('[IE] session DONE', provider.debugName);
}
accept(preview: boolean = this._preview): void {
this._zone.widget.acceptInput(preview);
}
private _preview: boolean = false; // TODO@jrieken persist this
togglePreview(): void {
this._preview = !this._preview;
this._ctxShowPreview.set(this._preview);
}
cancelCurrentRequest(): void {
this._ctsRequest?.cancel();
}
cancelSession() {
this._ctsSession.cancel();
}
arrowOut(up: boolean): void {
if (this._zone.position && this._editor.hasModel()) {
const { column } = this._editor.getPosition();
const { lineNumber } = this._zone.position;
const newLine = up ? lineNumber : lineNumber + 1;
this._editor.setPosition({ lineNumber: newLine, column });
this._editor.focus();
}
}
focus(): void {
this._zone.widget.focus();
}
populateHistory(up: boolean) {
const len = InteractiveEditorController._promptHistory.length;
if (len === 0) {
return;
}
const pos = (len + this._historyOffset + (up ? 1 : -1)) % len;
const entry = InteractiveEditorController._promptHistory[pos];
this._zone.widget.populateInputField(entry);
this._historyOffset = pos;
}
toggleHistory(): void {
this._zone.widget.toggleHistory();
}
}

View file

@ -0,0 +1,66 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IRange } from 'vs/editor/common/core/range';
import { ISelection } from 'vs/editor/common/core/selection';
import { ProviderResult, TextEdit } from 'vs/editor/common/languages';
import { ITextModel } from 'vs/editor/common/model';
import { localize } from 'vs/nls';
import { MenuId } from 'vs/platform/actions/common/actions';
import { RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
export interface IInteractiveEditorSession {
id: number;
placeholder?: string;
dispose?(): void;
}
export interface IInteractiveEditorRequest {
session: IInteractiveEditorSession;
prompt: string;
// model: ITextModel;
selection: ISelection;
wholeRange: IRange;
}
export interface IInteractiveEditorResponse {
// item: IInputModeSession;
edits: TextEdit[]; // WorkspaceEdit?
placeholder?: string;
}
export interface IInteractiveEditorSessionProvider {
debugName: string;
prepareInteractiveEditorSession(model: ITextModel, range: ISelection, token: CancellationToken): ProviderResult<IInteractiveEditorSession>;
provideResponse(item: IInteractiveEditorSession, request: IInteractiveEditorRequest, token: CancellationToken): ProviderResult<IInteractiveEditorResponse>;
}
export const IInteractiveEditorService = createDecorator<IInteractiveEditorService>('IInteractiveEditorService');
export interface IInteractiveEditorService {
_serviceBrand: undefined;
add(provider: IInteractiveEditorSessionProvider): IDisposable;
getAll(): Iterable<IInteractiveEditorSessionProvider>;
}
export const MENU_INTERACTIVE_EDITOR_WIDGET_LHS = MenuId.for('interactiveEditorWidgetLhs');
export const MENU_INTERACTIVE_EDITOR_WIDGET = MenuId.for('interactiveEditorWidgetRhs');
export const CTX_INTERACTIVE_EDITOR_HAS_PROVIDER = new RawContextKey<boolean>('interactiveEditorHasProvider', false, localize('interactiveEditorHasProvider', "Whether a provider for interactive editors exists"));
export const CTX_INTERACTIVE_EDITOR_VISIBLE = new RawContextKey<boolean>('interactiveEditorVisible', false, localize('interactiveEditorVisible', "Whether the interactive editor input is visible"));
export const CTX_INTERACTIVE_EDITOR_FOCUSED = new RawContextKey<boolean>('interactiveEditorFocused', false, localize('interactiveEditorFocused', "Whether the interactive editor input is focused"));
export const CTX_INTERACTIVE_EDITOR_EMPTY = new RawContextKey<boolean>('interactiveEditorEmpty', false, localize('interactiveEditorEmpty', "Whether the interactive editor input is empty"));
export const CTX_INTERACTIVE_EDITOR_PREVIEW = new RawContextKey<boolean>('interactiveEditorPreview', false, localize('interactiveEditorPreview', "Whether the interactive editor input shows inline previews"));
export const CTX_INTERACTIVE_EDITOR_HISTORY_VISIBLE = new RawContextKey<boolean>('interactiveEditorHistoryVisible', false, localize('interactiveEditorHistoryVisible', "Whether the interactive editor history is visible"));
export const CTX_INTERACTIVE_EDITOR_INNER_CURSOR_FIRST = new RawContextKey<boolean>('interactiveEditorInnerCursorFirst', false, localize('interactiveEditorInnerCursorFirst', "Whether the cursor of the iteractive editor input is on the first line"));
export const CTX_INTERACTIVE_EDITOR_INNER_CURSOR_LAST = new RawContextKey<boolean>('interactiveEditorInnerCursorLast', false, localize('interactiveEditorInnerCursorLast', "Whether the cursor of the iteractive editor input is on the last line"));
export const CTX_INTERACTIVE_EDITOR_OUTER_CURSOR_POSITION = new RawContextKey<'above' | 'below' | ''>('interactiveEditorOuterCursorPosition', '', localize('interactiveEditorOuterCursorPosition', "Whether the cursor of the outer editor is above or below the interactive editor input"));
export const CTX_INTERACTIVE_EDITOR_HAS_ACTIVE_REQUEST = new RawContextKey<boolean>('interactiveEditorHasActiveRequest', false, localize('interactiveEditorHasActiveRequest', "Whether interactive editor has an active request"));

View file

@ -0,0 +1,37 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { LinkedList } from 'vs/base/common/linkedList';
import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInteractiveEditorService, IInteractiveEditorSessionProvider, CTX_INTERACTIVE_EDITOR_HAS_PROVIDER } from './interactiveEditor';
export class InteractiveEditorServiceImpl implements IInteractiveEditorService {
declare _serviceBrand: undefined;
private readonly _entries = new LinkedList<IInteractiveEditorSessionProvider>();
private readonly _ctxHasProvider: IContextKey<boolean>;
constructor(@IContextKeyService contextKeyService: IContextKeyService) {
this._ctxHasProvider = CTX_INTERACTIVE_EDITOR_HAS_PROVIDER.bindTo(contextKeyService);
}
add(provider: IInteractiveEditorSessionProvider): IDisposable {
const rm = this._entries.push(provider);
this._ctxHasProvider.set(true);
return toDisposable(() => {
rm();
this._ctxHasProvider.set(this._entries.size > 0);
});
}
getAll() {
return [...this._entries];
}
}

View file

@ -26,7 +26,7 @@ import { createActionViewItem } from 'vs/platform/actions/browser/menuEntryActio
import { IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { createDecorator, IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
import { activeContrastBorder, contrastBorder, editorForeground, editorInfoForeground, registerColor, transparent } from 'vs/platform/theme/common/colorRegistry';
import { activeContrastBorder, contrastBorder, editorForeground, editorInfoForeground, registerColor } from 'vs/platform/theme/common/colorRegistry';
export const IPeekViewService = createDecorator<IPeekViewService>('IPeekViewService');
export interface IPeekViewService {
@ -278,7 +278,7 @@ export abstract class PeekViewWidget extends ZoneWidget {
}
export const peekViewTitleBackground = registerColor('peekViewTitle.background', { dark: transparent(editorInfoForeground, .1), light: transparent(editorInfoForeground, .1), hcDark: null, hcLight: null }, nls.localize('peekViewTitleBackground', 'Background color of the peek view title area.'));
export const peekViewTitleBackground = registerColor('peekViewTitle.background', { dark: '#252526', light: '#F3F3F3', hcDark: Color.black, hcLight: Color.white }, nls.localize('peekViewTitleBackground', 'Background color of the peek view title area.'));
export const peekViewTitleForeground = registerColor('peekViewTitleLabel.foreground', { dark: Color.white, light: Color.black, hcDark: Color.white, hcLight: editorForeground }, nls.localize('peekViewTitleForeground', 'Color of the peek view title.'));
export const peekViewTitleInfoForeground = registerColor('peekViewTitleDescription.foreground', { dark: '#ccccccb3', light: '#616161', hcDark: '#FFFFFF99', hcLight: '#292929' }, nls.localize('peekViewTitleInfoForeground', 'Color of the peek view title info.'));
export const peekViewBorder = registerColor('peekView.border', { dark: editorInfoForeground, light: editorInfoForeground, hcDark: contrastBorder, hcLight: contrastBorder }, nls.localize('peekViewBorder', 'Color of the peek view borders and arrow.'));

View file

@ -35,7 +35,7 @@
.monaco-editor .sticky-widget {
width: 100%;
box-shadow: var(--vscode-scrollbar-shadow) 0 3px 2px -2px;
z-index: 11;
z-index: 4;
background-color: var(--vscode-editorStickyScroll-background);
}

View file

@ -706,7 +706,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
return withOracle(async (sugget, editor) => {
class TestCtrl extends SuggestController {
override _insertSuggestion(item: ISelectedSuggestion, flags: number = 0) {
_insertSuggestion_publicForTest(item: ISelectedSuggestion, flags: number = 0) {
super._insertSuggestion(item, flags);
}
}
@ -722,7 +722,7 @@ suite('SuggestModel - TriggerAndCancelOracle', function () {
const [first] = event.completionModel.items;
assert.strictEqual(first.completion.label, 'bar');
ctrl._insertSuggestion({ item: first, index: 0, model: event.completionModel });
ctrl._insertSuggestion_publicForTest({ item: first, index: 0, model: event.completionModel });
});
assert.strictEqual(

View file

@ -9,7 +9,7 @@ import { Codicon } from 'vs/base/common/codicons';
import { MarkdownString } from 'vs/base/common/htmlContent';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import * as platform from 'vs/base/common/platform';
import { InvisibleCharacters } from 'vs/base/common/strings';
import { InvisibleCharacters, isBasicASCII } from 'vs/base/common/strings';
import 'vs/css!./unicodeHighlighter';
import { IActiveCodeEditor, ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { EditorAction, EditorContributionInstantiation, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions';
@ -444,14 +444,24 @@ export class UnicodeHighlighterHoverParticipant implements IEditorHoverParticipa
let reason: string;
switch (highlightInfo.reason.kind) {
case UnicodeHighlighterReasonKind.Ambiguous:
reason = nls.localize(
'unicodeHighlight.characterIsAmbiguous',
'The character {0} could be confused with the character {1}, which is more common in source code.',
codePointStr,
formatCodePointMarkdown(highlightInfo.reason.confusableWith.codePointAt(0)!)
);
case UnicodeHighlighterReasonKind.Ambiguous: {
if (isBasicASCII(highlightInfo.reason.confusableWith)) {
reason = nls.localize(
'unicodeHighlight.characterIsAmbiguousASCII',
'The character {0} could be confused with the ASCII character {1}, which is more common in source code.',
codePointStr,
formatCodePointMarkdown(highlightInfo.reason.confusableWith.codePointAt(0)!)
);
} else {
reason = nls.localize(
'unicodeHighlight.characterIsAmbiguous',
'The character {0} could be confused with the character {1}, which is more common in source code.',
codePointStr,
formatCodePointMarkdown(highlightInfo.reason.confusableWith.codePointAt(0)!)
);
}
break;
}
case UnicodeHighlighterReasonKind.Invisible:
reason = nls.localize(

View file

@ -245,6 +245,14 @@ class WordHighlighter {
this._run();
}
public stop(): void {
if (!this.occurrencesHighlight) {
return;
}
this._stopAll();
}
private _getSortedHighlights(): Range[] {
return (
this.decorations.getRanges()
@ -453,7 +461,7 @@ class WordHighlighter {
}
}
class WordHighlighterContribution extends Disposable implements IEditorContribution {
export class WordHighlighterContribution extends Disposable implements IEditorContribution {
public static readonly ID = 'editor.contrib.wordHighlighter';
@ -502,6 +510,10 @@ class WordHighlighterContribution extends Disposable implements IEditorContribut
}
}
public stopHighlighting() {
this.wordHighlighter?.stop();
}
public override dispose(): void {
if (this.wordHighlighter) {
this.wordHighlighter.dispose();

View file

@ -261,7 +261,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider {
}
}
private _getWidth(info: EditorLayoutInfo): number {
protected _getWidth(info: EditorLayoutInfo): number {
return info.width - info.minimap.minimapWidth - info.verticalScrollbarWidth;
}

View file

@ -57,6 +57,7 @@ import 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
import 'vs/editor/contrib/wordOperations/browser/wordOperations';
import 'vs/editor/contrib/wordPartOperations/browser/wordPartOperations';
import 'vs/editor/contrib/readOnlyMessage/browser/contribution';
import 'vs/editor/contrib/interactive/browser/interactiveEditor.contribution';
// Load up these strings even in VSCode, even if they are not used
// in order to get them translated

View file

@ -470,7 +470,7 @@ export class StandaloneEditor extends StandaloneCodeEditor implements IStandalon
super.updateOptions(newOptions);
}
override _postDetachModelCleanup(detachedModel: ITextModel): void {
protected override _postDetachModelCleanup(detachedModel: ITextModel): void {
super._postDetachModelCleanup(detachedModel);
if (detachedModel && this._ownsModel) {
detachedModel.dispose();

View file

@ -88,7 +88,7 @@ suite('EditorSimpleWorker', () => {
test('MoreMinimal', () => {
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }]).then(edits => {
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: 'This is line One', range: new Range(1, 1, 1, 17) }], false).then(edits => {
assert.strictEqual(edits.length, 1);
const [first] = edits;
assert.strictEqual(first.text, 'O');
@ -104,7 +104,7 @@ suite('EditorSimpleWorker', () => {
'}'
], '\n');
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => {
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"a":1\r\n}', range: new Range(1, 1, 3, 2) }], false).then(edits => {
assert.strictEqual(edits.length, 0);
});
});
@ -117,7 +117,7 @@ suite('EditorSimpleWorker', () => {
'}'
], '\n');
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }]).then(edits => {
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '{\r\n\t"b":1\r\n}', range: new Range(1, 1, 3, 2) }], false).then(edits => {
assert.strictEqual(edits.length, 1);
const [first] = edits;
assert.strictEqual(first.text, 'b');
@ -125,7 +125,7 @@ suite('EditorSimpleWorker', () => {
});
});
test('MoreMinimal, issue #15385 newline changes and other', function () {
test('MoreMinimal, issue #15385 newline changes and other 2/2', function () {
const model = worker.addModel([
'package main', // 1
@ -133,7 +133,7 @@ suite('EditorSimpleWorker', () => {
'}' // 3
]);
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }]).then(edits => {
return worker.computeMoreMinimalEdits(model.uri.toString(), [{ text: '\n', range: new Range(3, 2, 4, 1000) }], false).then(edits => {
assert.strictEqual(edits.length, 1);
const [first] = edits;
assert.strictEqual(first.text, '\n');

1
src/vs/monaco.d.ts vendored
View file

@ -1552,6 +1552,7 @@ declare namespace monaco.editor {
* In this case, the range must be empty and set to the last line.
*/
blockIsAfterEnd?: boolean | null;
blockDoesNotCollapse?: boolean | null;
blockPadding?: [top: number, right: number, bottom: number, left: number] | null;
/**
* Message to be rendered when hovering over the glyph margin decoration.

View file

@ -59,6 +59,7 @@ export class MenuId {
static readonly EditorContext = new MenuId('EditorContext');
static readonly SimpleEditorContext = new MenuId('SimpleEditorContext');
static readonly EditorContent = new MenuId('EditorContent');
static readonly EditorLineNumberContext = new MenuId('EditorLineNumberContext');
static readonly EditorContextCopy = new MenuId('EditorContextCopy');
static readonly EditorContextPeek = new MenuId('EditorContextPeek');
static readonly EditorContextShare = new MenuId('EditorContextShare');
@ -439,6 +440,8 @@ export class MenuItemAction implements IAction {
this.enabled = !item.precondition || contextKeyService.contextMatchesRules(item.precondition);
this.checked = undefined;
let icon: ThemeIcon | undefined;
if (item.toggled) {
const toggled = ((item.toggled as { condition: ContextKeyExpression }).condition ? item.toggled : { condition: item.toggled }) as {
condition: ContextKeyExpression; icon?: Icon; tooltip?: string | ILocalizedString; title?: string | ILocalizedString;
@ -448,17 +451,24 @@ export class MenuItemAction implements IAction {
this.tooltip = typeof toggled.tooltip === 'string' ? toggled.tooltip : toggled.tooltip.value;
}
if (this.checked && ThemeIcon.isThemeIcon(toggled.icon)) {
icon = toggled.icon;
}
if (toggled.title) {
this.label = typeof toggled.title === 'string' ? toggled.title : toggled.title.value;
}
}
if (!icon) {
icon = ThemeIcon.isThemeIcon(item.icon) ? item.icon : undefined;
}
this.item = item;
this.alt = alt ? new MenuItemAction(alt, undefined, options, hideActions, contextKeyService, _commandService) : undefined;
this._options = options;
if (ThemeIcon.isThemeIcon(item.icon)) {
this.class = ThemeIcon.asClassName(item.icon);
}
this.class = icon && ThemeIcon.asClassName(icon);
}
run(...args: any[]): Promise<void> {

View file

@ -35,8 +35,8 @@ export type Token =
| { type: TokenType.LParen; offset: number }
| { type: TokenType.RParen; offset: number }
| { type: TokenType.Neg; offset: number }
| { type: TokenType.Eq; offset: number }
| { type: TokenType.NotEq; offset: number }
| { type: TokenType.Eq; offset: number; isTripleEq: boolean }
| { type: TokenType.NotEq; offset: number; isTripleEq: boolean }
| { type: TokenType.Lt; offset: number }
| { type: TokenType.LtEq; offset: number }
| { type: TokenType.Gt; offset: number }
@ -59,8 +59,6 @@ type TokenTypeWithoutLexeme =
TokenType.LParen |
TokenType.RParen |
TokenType.Neg |
TokenType.Eq |
TokenType.NotEq |
TokenType.Lt |
TokenType.LtEq |
TokenType.Gt |
@ -98,7 +96,6 @@ function hintDidYouMean(...meant: string[]) {
}
}
const hintDontSupportTripleEq = localize('contextkey.scanner.hint.dontSupportTripleEq', "The '===' operator is not supported. Use '==' instead.");
const hintDidYouForgetToOpenOrCloseQuote = localize('contextkey.scanner.hint.didYouForgetToOpenOrCloseQuote', "Did you forget to open or close the quote?");
const hintDidYouForgetToEscapeSlash = localize('contextkey.scanner.hint.didYouForgetToEscapeSlash', "Did you forget to escape the '/' (slash) character? Put two backslashes before it to escape, e.g., '\\\\/\'.");
@ -128,9 +125,9 @@ export class Scanner {
case TokenType.Neg:
return '!';
case TokenType.Eq:
return '==';
return token.isTripleEq ? '===' : '==';
case TokenType.NotEq:
return '!=';
return token.isTripleEq ? '!==' : '!=';
case TokenType.Lt:
return '<';
case TokenType.LtEq:
@ -209,7 +206,12 @@ export class Scanner {
case CharCode.CloseParen: this._addToken(TokenType.RParen); break;
case CharCode.ExclamationMark:
this._addToken(this._match(CharCode.Equals) ? TokenType.NotEq : TokenType.Neg);
if (this._match(CharCode.Equals)) {
const isTripleEq = this._match(CharCode.Equals); // eat last `=` if `!==`
this._tokens.push({ type: TokenType.NotEq, offset: this._start, isTripleEq });
} else {
this._addToken(TokenType.Neg);
}
break;
case CharCode.SingleQuote: this._quotedString(); break;
@ -217,15 +219,12 @@ export class Scanner {
case CharCode.Equals:
if (this._match(CharCode.Equals)) { // support `==`
this._addToken(TokenType.Eq);
const isTripleEq = this._match(CharCode.Equals); // eat last `=` if `===`
this._tokens.push({ type: TokenType.Eq, offset: this._start, isTripleEq });
} else if (this._match(CharCode.Tilde)) {
this._addToken(TokenType.RegexOp);
} else {
if (this._tokens.length === 0 || this._tokens[this._tokens.length - 1].type !== TokenType.Eq) {
this._error(hintDidYouMean('==', '=~'));
} else {
this._error(hintDontSupportTripleEq);
}
this._error(hintDidYouMean('==', '=~'));
}
break;
@ -294,7 +293,7 @@ export class Scanner {
private _error(additional?: string) {
const offset = this._start;
const lexeme = this._input.substring(this._start, this._current);
const errToken = { type: TokenType.Error, offset: this._start, lexeme };
const errToken: Token = { type: TokenType.Error, offset: this._start, lexeme };
this._errors.push({ offset, lexeme, additionalInfo: additional });
this._tokens.push(errToken);
}

View file

@ -15,9 +15,9 @@ suite('Context Key Scanner', () => {
case TokenType.Neg:
return '!';
case TokenType.Eq:
return '==';
return token.isTripleEq ? '===' : '==';
case TokenType.NotEq:
return '!=';
return token.isTripleEq ? '!==' : '!=';
case TokenType.Lt:
return '<';
case TokenType.LtEq:
@ -53,6 +53,7 @@ suite('Context Key Scanner', () => {
}
}
function scan(input: string) {
return (new Scanner()).reset(input).scan().map((token: Token) => {
return 'lexeme' in token
@ -79,6 +80,16 @@ suite('Context Key Scanner', () => {
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "Str", lexeme: "foo", offset: 1 }, { type: "EOF", offset: 4 }]));
});
test('foo === bar', () => {
const input = 'foo === bar';
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "EOF", offset: 11 }]));
});
test('foo !== bar', () => {
const input = 'foo !== bar';
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "!==", offset: 5 }, { type: "Str", offset: 9, lexeme: "bar" }, { type: "EOF", offset: 12 }]));
});
test('!(foo && bar)', () => {
const input = '!(foo && bar)';
assert.deepStrictEqual(scan(input), ([{ type: "!", offset: 0 }, { type: "(", offset: 1 }, { type: "Str", lexeme: "foo", offset: 2 }, { type: "&&", offset: 6 }, { type: "Str", lexeme: "bar", offset: 9 }, { type: ")", offset: 12 }, { type: "EOF", offset: 13 }]));
@ -181,11 +192,16 @@ suite('Context Key Scanner', () => {
});
});
test(`foo === bar'`, () => {
const input = `foo === bar'`;
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "ErrorToken", offset: 11, lexeme: "'" }, { type: "EOF", offset: 12 }]));
});
suite('handling lexical errors', () => {
test(`foo === '`, () => {
const input = `foo === '`;
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "==", offset: 4 }, { type: "ErrorToken", offset: 6, lexeme: "=" }, { type: "ErrorToken", offset: 8, lexeme: "'" }, { type: "EOF", offset: 9 }]));
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "===", offset: 4 }, { type: "ErrorToken", offset: 8, lexeme: "'" }, { type: "EOF", offset: 9 }]));
});
test(`foo && 'bar - unterminated single quote`, () => {
@ -193,11 +209,6 @@ suite('Context Key Scanner', () => {
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "foo", offset: 0 }, { type: "&&", offset: 4 }, { type: "ErrorToken", offset: 7, lexeme: "'bar" }, { type: "EOF", offset: 11 }]));
});
test(`foo === bar'`, () => {
const input = `foo === bar'`;
assert.deepStrictEqual(scan(input), ([{ type: "Str", offset: 0, lexeme: "foo" }, { type: "==", offset: 4 }, { type: "ErrorToken", offset: 6, lexeme: "=" }, { type: "Str", offset: 8, lexeme: "bar" }, { type: "ErrorToken", offset: 11, lexeme: "'" }, { type: "EOF", offset: 12 }]));
});
test('vim<c-r> == 1 && vim<2 <= 3', () => {
const input = 'vim<c-r> == 1 && vim<2 <= 3';
assert.deepStrictEqual(scan(input), ([{ type: "Str", lexeme: "vim<c-r>", offset: 0 }, { type: "==", offset: 9 }, { type: "Str", lexeme: "1", offset: 12 }, { type: "&&", offset: 14 }, { type: "Str", lexeme: "vim<2", offset: 17 }, { type: "<=", offset: 23 }, { type: "Str", lexeme: "3", offset: 26 }, { type: "EOF", offset: 27 }]));

View file

@ -58,7 +58,7 @@ export abstract class BaseCredentialsMainService extends Disposable implements I
return null;
}
return this._sequencer.queue(service + account, () => this.doGetPassword(keytar, service, account));
return await this._sequencer.queue(service + account, () => this.doGetPassword(keytar, service, account));
}
private async doGetPassword(keytar: KeytarModule, service: string, account: string): Promise<string | null> {
@ -113,22 +113,30 @@ export abstract class BaseCredentialsMainService extends Disposable implements I
}
await this._sequencer.queue(service + account, () => this.doSetPassword(keytar, service, account, password));
this._onDidChangePassword.fire({ service, account });
}
private async doSetPassword(keytar: KeytarModule, service: string, account: string, password: string): Promise<void> {
if (!isWindows) {
await retry(() => keytar.setPassword(service, account, password), 50, 3);
this.logService.trace('Set password from keytar for account:', account);
this._onDidChangePassword.fire({ service, account });
return;
}
// On Windows, we have to chunk the password because the Windows Credential Manager only allows passwords of a max length.
// So to make sure we can store passwords of any length, we chunk the password and store it as multiple passwords.
// To ensure we store an password correctly, we first delete any existing password chunks and then store the new ones.
// On Windows, we sometimes have to chunk the password because the Windows Credential Manager only allows passwords of a max length.
// So to make sure we can store passwords of any length, we chunk the longer passwords and store it as multiple passwords.
// To ensure we store any password correctly, we first delete any existing password, chunks and all, and then store the new ones.
await this.doDeletePassword(keytar, service, account);
// if it's a short password, just store it
if (password.length <= BaseCredentialsMainService.PASSWORD_CHUNK_SIZE) {
await retry(() => keytar.setPassword(service, account, password), 50, 3);
this.logService.trace('Set password from keytar for account:', account);
return;
}
// otherwise, chunk it and store it
let index = 0;
let chunk = 0;
let hasNextChunk = true;
@ -149,7 +157,6 @@ export abstract class BaseCredentialsMainService extends Disposable implements I
await Promise.all(promises);
this.logService.trace(`Set${chunk ? ` ${chunk}-chunked` : ''} password from keytar for account:`, account);
this._onDidChangePassword.fire({ service, account });
}
async deletePassword(service: string, account: string): Promise<boolean> {
@ -162,7 +169,11 @@ export abstract class BaseCredentialsMainService extends Disposable implements I
throw e;
}
return await this._sequencer.queue(service + account, () => this.doDeletePassword(keytar, service, account));
const result = await this._sequencer.queue(service + account, () => this.doDeletePassword(keytar, service, account));
if (result) {
this._onDidChangePassword.fire({ service, account });
}
return result;
}
private async doDeletePassword(keytar: KeytarModule, service: string, account: string): Promise<boolean> {
@ -208,7 +219,6 @@ export abstract class BaseCredentialsMainService extends Disposable implements I
// Delete the first account to determine deletion success
if (await keytar.deletePassword(service, account)) {
this._onDidChangePassword.fire({ service, account });
this.logService.trace(`Deleted${index ? ` ${index}-chunked` : ''} password from keytar for account:`, account);
return true;
}

View file

@ -196,7 +196,8 @@ export class ExtensionManagementCLI {
private async getGalleryExtensions(extensions: InstallExtensionInfo[]): Promise<Map<string, IGalleryExtension>> {
const galleryExtensions = new Map<string, IGalleryExtension>();
const preRelease = extensions.some(e => e.installOptions.installPreReleaseVersion);
const result = await this.extensionGalleryService.getExtensions(extensions.map(e => ({ ...e, preRelease })), CancellationToken.None);
const targetPlatform = await this.extensionManagementService.getTargetPlatform();
const result = await this.extensionGalleryService.getExtensions(extensions.map(e => ({ ...e, preRelease })), { targetPlatform }, CancellationToken.None);
for (const extension of result) {
galleryExtensions.set(extension.identifier.id.toLowerCase(), extension);
}

View file

@ -5,7 +5,7 @@
import { compareIgnoreCase } from 'vs/base/common/strings';
import { IExtensionIdentifier, IGalleryExtension, ILocalExtension, getTargetPlatform } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionIdentifier, IExtension, TargetPlatform } from 'vs/platform/extensions/common/extensions';
import { ExtensionIdentifier, IExtension, TargetPlatform, UNDEFINED_PUBLISHER } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { isLinux, platform } from 'vs/base/common/platform';
import { URI } from 'vs/base/common/uri';
@ -78,8 +78,8 @@ export function adoptToGalleryExtensionId(id: string): string {
return id.toLocaleLowerCase();
}
export function getGalleryExtensionId(publisher: string, name: string): string {
return adoptToGalleryExtensionId(getExtensionId(publisher, name));
export function getGalleryExtensionId(publisher: string | undefined, name: string): string {
return adoptToGalleryExtensionId(getExtensionId(publisher ?? UNDEFINED_PUBLISHER, name));
}
export function groupByExtension<T>(extensions: T[], getExtensionIdentifier: (t: T) => IExtensionIdentifier): T[][] {

View file

@ -30,6 +30,7 @@ export interface IExtensionHostStarter {
onDynamicError(id: string): Event<{ error: SerializedError }>;
onDynamicExit(id: string): Event<{ code: number; signal: string }>;
canUseUtilityProcess(): Promise<boolean>;
createExtensionHost(useUtilityProcess: boolean): Promise<{ id: string }>;
start(id: string, opts: IExtensionHostProcessOptions): Promise<void>;
enableInspectPort(id: string): Promise<boolean>;

View file

@ -17,6 +17,7 @@ import { FileAccess } from 'vs/base/common/network';
import { mixin } from 'vs/base/common/objects';
import * as platform from 'vs/base/common/platform';
import { cwd } from 'vs/base/common/process';
import { canUseUtilityProcess } from 'vs/base/parts/sandbox/electron-main/electronTypes';
import { WindowUtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@ -81,6 +82,10 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
return this._getExtHost(id).onExit;
}
async canUseUtilityProcess(): Promise<boolean> {
return canUseUtilityProcess;
}
async createExtensionHost(useUtilityProcess: boolean): Promise<{ id: string }> {
if (this._shutdown) {
throw canceled();
@ -88,6 +93,9 @@ export class ExtensionHostStarter implements IDisposable, IExtensionHostStarter
const id = String(++ExtensionHostStarter._lastId);
let extHost: WindowUtilityProcess | ExtensionHostProcess;
if (useUtilityProcess) {
if (!canUseUtilityProcess) {
throw new Error(`Cannot use UtilityProcess!`);
}
extHost = new WindowUtilityProcess(this._logService, this._windowsMainService, this._telemetryService, this._lifecycleMainService);
} else {
extHost = new ExtensionHostProcess(id, this._logService);

View file

@ -59,8 +59,8 @@ export abstract class AbstractRequestService extends Disposable implements IRequ
loggerService: ILoggerService
) {
super();
this.logger = loggerService.createLogger('request', {
name: remote ? localize('remote request', "Remote Network Requests") : localize('request', "Network Requests"),
this.logger = loggerService.createLogger(remote ? 'remotenetwork' : 'network', {
name: remote ? localize('remote request', "Network Requests (Remote)") : localize('request', "Network Requests"),
when: CONTEXT_LOG_LEVEL.isEqualTo(LogLevelToString(LogLevel.Trace)).serialize()
});
}

View file

@ -28,6 +28,7 @@ import { ILoggerMainService } from 'vs/platform/log/electron-main/loggerService'
import { UtilityProcess } from 'vs/platform/utilityProcess/electron-main/utilityProcess';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { canUseUtilityProcess } from 'vs/base/parts/sandbox/electron-main/electronTypes';
import { parseSharedProcessDebugPort } from 'vs/platform/environment/node/environmentService';
export class SharedProcess extends Disposable implements ISharedProcess {
@ -43,11 +44,13 @@ export class SharedProcess extends Disposable implements ISharedProcess {
private utilityProcess: UtilityProcess | undefined = undefined;
private readonly useUtilityProcess = (() => {
let useUtilityProcess = false;
const sharedProcessUseUtilityProcess = this.configurationService.getValue<boolean>('window.experimental.sharedProcessUseUtilityProcess');
if (typeof sharedProcessUseUtilityProcess === 'boolean') {
useUtilityProcess = sharedProcessUseUtilityProcess;
} else {
useUtilityProcess = product.quality !== 'stable';
if (canUseUtilityProcess) {
const sharedProcessUseUtilityProcess = this.configurationService.getValue<boolean>('window.experimental.sharedProcessUseUtilityProcess');
if (typeof sharedProcessUseUtilityProcess === 'boolean') {
useUtilityProcess = sharedProcessUseUtilityProcess;
} else {
useUtilityProcess = typeof product.quality === 'string' && product.quality !== 'stable';
}
}
return useUtilityProcess;

View file

@ -3,13 +3,14 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { BrowserWindow, Details, MessageChannelMain, app, utilityProcess, UtilityProcess as ElectronUtilityProcess } from 'electron';
import { BrowserWindow, Details, app, MessageChannelMain, MessagePortMain } from 'electron';
import { Disposable } from 'vs/base/common/lifecycle';
import { Emitter, Event } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { StringDecoder } from 'string_decoder';
import { timeout } from 'vs/base/common/async';
import { FileAccess } from 'vs/base/common/network';
import { UtilityProcess as ElectronUtilityProcess, UtilityProcessProposedApi, canUseUtilityProcess } from 'vs/base/parts/sandbox/electron-main/electronTypes';
import { IWindowsMainService } from 'vs/platform/windows/electron-main/windows';
import Severity from 'vs/base/common/severity';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
@ -154,7 +155,7 @@ export class UtilityProcess extends Disposable {
private readonly _onCrash = this._register(new Emitter<IUtilityProcessCrashEvent>());
readonly onCrash = this._onCrash.event;
private process: ElectronUtilityProcess | undefined = undefined;
private process: UtilityProcessProposedApi.UtilityProcess | undefined = undefined;
private processPid: number | undefined = undefined;
private configuration: IUtilityProcessConfiguration | undefined = undefined;
@ -188,6 +189,10 @@ export class UtilityProcess extends Disposable {
}
private validateCanStart(): boolean {
if (!canUseUtilityProcess) {
throw new Error('Cannot use UtilityProcess API from Electron!');
}
if (this.process) {
this.log('Cannot start utility process because it is already running...', Severity.Error);
@ -225,7 +230,7 @@ export class UtilityProcess extends Disposable {
this.log('creating new...', Severity.Info);
// Fork utility process
this.process = utilityProcess.fork(modulePath, args, {
this.process = ElectronUtilityProcess.fork(modulePath, args, {
serviceName,
env,
execArgv,
@ -263,7 +268,7 @@ export class UtilityProcess extends Disposable {
return env;
}
private registerListeners(process: ElectronUtilityProcess, configuration: IUtilityProcessConfiguration, serviceName: string, isWindowSandboxed: boolean): void {
private registerListeners(process: UtilityProcessProposedApi.UtilityProcess, configuration: IUtilityProcessConfiguration, serviceName: string, isWindowSandboxed: boolean): void {
// Stdout
if (process.stdout) {
@ -356,7 +361,7 @@ export class UtilityProcess extends Disposable {
this.process.postMessage(message, transfer);
}
connect(payload?: unknown): Electron.MessagePortMain {
connect(payload?: unknown): MessagePortMain {
const { port1: outPort, port2: utilityProcessPort } = new MessageChannelMain();
this.postMessage(payload, [utilityProcessPort]);

View file

@ -54,6 +54,7 @@ import { IUserDataProfile } from 'vs/platform/userDataProfile/common/userDataPro
import { IPolicyService } from 'vs/platform/policy/common/policy';
import { IUserDataProfilesMainService } from 'vs/platform/userDataProfile/electron-main/userDataProfile';
import { ILoggerMainService } from 'vs/platform/log/electron-main/loggerService';
import { canUseUtilityProcess } from 'vs/base/parts/sandbox/electron-main/electronTypes';
//#region Helper Interfaces
@ -1324,10 +1325,12 @@ export class WindowsMainService extends Disposable implements IWindowsMainServic
}
let preferUtilityProcess = false;
if (typeof windowConfig?.experimental?.sharedProcessUseUtilityProcess === 'boolean') {
preferUtilityProcess = windowConfig.experimental.sharedProcessUseUtilityProcess;
} else {
preferUtilityProcess = product.quality !== 'stable';
if (canUseUtilityProcess) {
if (typeof windowConfig?.experimental?.sharedProcessUseUtilityProcess === 'boolean') {
preferUtilityProcess = windowConfig.experimental.sharedProcessUseUtilityProcess;
} else {
preferUtilityProcess = typeof product.quality === 'string' && product.quality !== 'stable';
}
}
// Build up the window configuration from provided options, config and environment

View file

@ -70,6 +70,7 @@ import './mainThreadNotebookKernels';
import './mainThreadNotebookDocumentsAndEditors';
import './mainThreadNotebookRenderers';
import './mainThreadInteractive';
import './mainThreadInteractiveEditor';
import './mainThreadInteractiveSession';
import './mainThreadTask';
import './mainThreadLabelService';

View file

@ -0,0 +1,54 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableMap } from 'vs/base/common/lifecycle';
import { IInteractiveEditorService } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { ExtHostContext, ExtHostInteractiveEditorShape, MainContext, MainThreadInteractiveEditorShape } from 'vs/workbench/api/common/extHost.protocol';
import { IExtHostContext, extHostNamedCustomer } from 'vs/workbench/services/extensions/common/extHostCustomers';
@extHostNamedCustomer(MainContext.MainThreadInteractiveEditor)
export class MainThreadInteractiveEditor implements MainThreadInteractiveEditorShape {
private readonly _registrations = new DisposableMap<number>();
private readonly _proxy: ExtHostInteractiveEditorShape;
constructor(
extHostContext: IExtHostContext,
@IInteractiveEditorService private readonly _interactiveEditorService: IInteractiveEditorService,
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostInteractiveEditor);
}
dispose(): void {
this._registrations.dispose();
}
async $registerInteractiveEditorProvider(handle: number, debugName: string): Promise<void> {
const unreg = this._interactiveEditorService.add({
debugName,
prepareInteractiveEditorSession: async (model, range, token) => {
const session = await this._proxy.$prepareInteractiveSession(handle, model.uri, range, token);
if (!session) {
return undefined;
}
return {
...session,
dispose: () => {
this._proxy.$releaseSession(handle, session.id);
}
};
},
provideResponse: (item, request, token) => {
return this._proxy.$provideResponse(handle, item, request, token);
}
});
this._registrations.set(handle, unreg);
}
async $unregisterInteractiveEditorProvider(handle: number): Promise<void> {
this._registrations.deleteAndDispose(handle);
}
}

View file

@ -98,6 +98,7 @@ import { EditSessionIdentityMatch } from 'vs/platform/workspace/common/editSessi
import { ExtHostProfileContentHandlers } from 'vs/workbench/api/common/extHostProfileContentHandler';
import { ExtHostQuickDiff } from 'vs/workbench/api/common/extHostQuickDiff';
import { ExtHostInteractiveSession } from 'vs/workbench/api/common/extHostInteractiveSession';
import { ExtHostInteractiveEditor } from 'vs/workbench/api/common/extHostInteractiveEditor';
export interface IExtensionRegistries {
mine: ExtensionDescriptionRegistry;
@ -192,6 +193,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostUriOpeners = rpcProtocol.set(ExtHostContext.ExtHostUriOpeners, new ExtHostUriOpeners(rpcProtocol));
const extHostProfileContentHandlers = rpcProtocol.set(ExtHostContext.ExtHostProfileContentHandlers, new ExtHostProfileContentHandlers(rpcProtocol));
rpcProtocol.set(ExtHostContext.ExtHostInteractive, new ExtHostInteractive(rpcProtocol, extHostNotebook, extHostDocumentsAndEditors, extHostCommands, extHostLogService));
const extHostInteractiveEditor = rpcProtocol.set(ExtHostContext.ExtHostInteractiveEditor, new ExtHostInteractiveEditor(rpcProtocol, extHostDocuments, extHostLogService));
const extHostInteractiveSession = rpcProtocol.set(ExtHostContext.ExtHostInteractiveSession, new ExtHostInteractiveSession(rpcProtocol, extHostLogService));
// Check that no named customers are missing
@ -1216,6 +1218,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// this needs to be updated whenever the API proposal changes
_version: 1,
registerInteractiveEditorSessionProvider(provider: vscode.InteractiveEditorSessionProvider) {
checkProposedApiEnabled(extension, 'interactive');
return extHostInteractiveEditor.registerProvider(extension, provider);
},
registerInteractiveSessionProvider(id: string, provider: vscode.InteractiveSessionProvider) {
checkProposedApiEnabled(extension, 'interactive');
return extHostInteractiveSession.registerInteractiveSessionProvider(extension, id, provider);

View file

@ -26,6 +26,7 @@ import * as languages from 'vs/editor/common/languages';
import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/languages/languageConfiguration';
import { EndOfLineSequence } from 'vs/editor/common/model';
import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel';
import { IInteractiveEditorResponse, IInteractiveEditorSession, IInteractiveEditorRequest } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { IAccessibilityInformation } from 'vs/platform/accessibility/common/accessibility';
import { ConfigurationTarget, IConfigurationChange, IConfigurationData, IConfigurationOverrides } from 'vs/platform/configuration/common/configuration';
import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry';
@ -1068,6 +1069,17 @@ export interface MainThreadNotebookRenderersShape extends IDisposable {
export interface MainThreadInteractiveShape extends IDisposable {
}
export interface MainThreadInteractiveEditorShape extends IDisposable {
$registerInteractiveEditorProvider(handle: number, debugName: string): Promise<void>;
$unregisterInteractiveEditorProvider(handle: number): Promise<void>;
}
export interface ExtHostInteractiveEditorShape {
$prepareInteractiveSession(handle: number, uri: UriComponents, range: ISelection, token: CancellationToken): Promise<IInteractiveEditorSession | undefined>;
$provideResponse(handle: number, session: IInteractiveEditorSession, request: IInteractiveEditorRequest, token: CancellationToken): Promise<IInteractiveEditorResponse | undefined>;
$releaseSession(handle: number, sessionId: number): void;
}
export interface MainThreadUrlsShape extends IDisposable {
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
$unregisterUriHandler(handle: number): Promise<void>;
@ -2411,6 +2423,7 @@ export const MainContext = {
MainThreadNotebookRenderers: createProxyIdentifier<MainThreadNotebookRenderersShape>('MainThreadNotebookRenderers'),
MainThreadInteractive: createProxyIdentifier<MainThreadInteractiveShape>('MainThreadInteractive'),
MainThreadInteractiveSession: createProxyIdentifier<MainThreadInteractiveSessionShape>('MainThreadInteractiveSession'),
MainThreadInteractiveEditor: createProxyIdentifier<MainThreadInteractiveEditorShape>('MainThreadInteractiveEditor'),
MainThreadTheming: createProxyIdentifier<MainThreadThemingShape>('MainThreadTheming'),
MainThreadTunnelService: createProxyIdentifier<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
MainThreadTimeline: createProxyIdentifier<MainThreadTimelineShape>('MainThreadTimeline'),
@ -2466,6 +2479,7 @@ export const ExtHostContext = {
ExtHostNotebookKernels: createProxyIdentifier<ExtHostNotebookKernelsShape>('ExtHostNotebookKernels'),
ExtHostNotebookRenderers: createProxyIdentifier<ExtHostNotebookRenderersShape>('ExtHostNotebookRenderers'),
ExtHostInteractive: createProxyIdentifier<ExtHostInteractiveShape>('ExtHostInteractive'),
ExtHostInteractiveEditor: createProxyIdentifier<ExtHostInteractiveEditorShape>('ExtHostInteractiveEditor'),
ExtHostInteractiveSession: createProxyIdentifier<ExtHostInteractiveSessionShape>('ExtHostInteractiveSession'),
ExtHostTheming: createProxyIdentifier<ExtHostThemingShape>('ExtHostTheming'),
ExtHostTunnelService: createProxyIdentifier<ExtHostTunnelServiceShape>('ExtHostTunnelService'),

View file

@ -0,0 +1,111 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { CancellationToken } from 'vs/base/common/cancellation';
import { toDisposable } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { ISelection } from 'vs/editor/common/core/selection';
import { IInteractiveEditorResponse, IInteractiveEditorSession, IInteractiveEditorRequest } from 'vs/editor/contrib/interactive/common/interactiveEditor';
import { IRelaxedExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostInteractiveEditorShape, IMainContext, MainContext, MainThreadInteractiveEditorShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
import * as typeConvert from 'vs/workbench/api/common/extHostTypeConverters';
import type * as vscode from 'vscode';
class ProviderWrapper {
private static _pool = 0;
readonly handle: number = ProviderWrapper._pool++;
constructor(
readonly extension: Readonly<IRelaxedExtensionDescription>,
readonly provider: vscode.InteractiveEditorSessionProvider,
) { }
}
export class ExtHostInteractiveEditor implements ExtHostInteractiveEditorShape {
private static _nextId = 0;
private readonly _inputProvider = new Map<number, ProviderWrapper>();
private readonly _inputSessions = new Map<number, vscode.InteractiveEditorSession>();
private readonly _proxy: MainThreadInteractiveEditorShape;
constructor(
mainContext: IMainContext,
private readonly _documents: ExtHostDocuments,
private readonly _logService: ILogService
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadInteractiveEditor);
}
registerProvider(extension: Readonly<IRelaxedExtensionDescription>, provider: vscode.InteractiveEditorSessionProvider): vscode.Disposable {
const wrapper = new ProviderWrapper(extension, provider);
this._inputProvider.set(wrapper.handle, wrapper);
this._proxy.$registerInteractiveEditorProvider(wrapper.handle, extension.identifier.value);
return toDisposable(() => {
this._proxy.$unregisterInteractiveEditorProvider(wrapper.handle);
this._inputProvider.delete(wrapper.handle);
});
}
async $prepareInteractiveSession(handle: number, uri: UriComponents, range: ISelection, token: CancellationToken): Promise<IInteractiveEditorSession | undefined> {
const entry = this._inputProvider.get(handle);
if (!entry) {
this._logService.warn('CANNOT prepare session because the PROVIDER IS GONE');
return undefined;
}
const document = this._documents.getDocument(URI.revive(uri));
const session = await entry.provider.prepareInteractiveEditorSession({ document, selection: typeConvert.Selection.to(range) }, token);
if (!session) {
return undefined;
}
const id = ExtHostInteractiveEditor._nextId++;
this._inputSessions.set(id, session);
return { id, placeholder: session.placeholder };
}
async $provideResponse(handle: number, item: IInteractiveEditorSession, request: IInteractiveEditorRequest, token: CancellationToken): Promise<IInteractiveEditorResponse | undefined> {
const entry = this._inputProvider.get(handle);
if (!entry) {
return undefined;
}
const session = this._inputSessions.get(item.id);
if (!session) {
return;
}
const res = await entry.provider.provideInteractiveEditorResponse({
session,
prompt: request.prompt,
selection: typeConvert.Selection.to(request.selection),
wholeRange: typeConvert.Range.to(request.wholeRange)
}, token);
if (!res) {
return;
}
return {
edits: res.edits.map(typeConvert.TextEdit.from),
placeholder: res.placeholder
};
}
$releaseSession(handle: number, sessionId: number) {
const session = this._inputSessions.get(sessionId);
const entry = this._inputProvider.get(handle);
if (session && entry) {
entry.provider.releaseInteractiveEditorSession?.(session);
}
this._inputSessions.delete(sessionId);
}
}

View file

@ -26,6 +26,7 @@ import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/
import type * as vscode from 'vscode';
import { ExtHostCell, ExtHostNotebookDocument } from './extHostNotebookDocument';
import { ExtHostNotebookEditor } from './extHostNotebookEditor';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
@ -41,7 +42,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
private readonly _commandsConverter: CommandsConverter;
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>();
private readonly _onDidChangeActiveNotebookEditor = new Emitter<vscode.NotebookEditor | undefined>({ onListenerError: onUnexpectedExternalError });
readonly onDidChangeActiveNotebookEditor = this._onDidChangeActiveNotebookEditor.event;
private _activeNotebookEditor: ExtHostNotebookEditor | undefined;
@ -53,12 +54,12 @@ export class ExtHostNotebookController implements ExtHostNotebookShape {
return this._visibleNotebookEditors.map(editor => editor.apiEditor);
}
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>();
private _onDidOpenNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
onDidOpenNotebookDocument: Event<vscode.NotebookDocument> = this._onDidOpenNotebookDocument.event;
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>();
private _onDidCloseNotebookDocument = new Emitter<vscode.NotebookDocument>({ onListenerError: onUnexpectedExternalError });
onDidCloseNotebookDocument: Event<vscode.NotebookDocument> = this._onDidCloseNotebookDocument.event;
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>();
private _onDidChangeVisibleNotebookEditors = new Emitter<vscode.NotebookEditor[]>({ onListenerError: onUnexpectedExternalError });
onDidChangeVisibleNotebookEditors = this._onDidChangeVisibleNotebookEditors.event;
private _statusBarCache = new Cache<IDisposable>('NotebookCellStatusBarCache');

View file

@ -3,6 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter } from 'vs/base/common/event';
import { ILogService } from 'vs/platform/log/common/log';
import { ExtHostNotebookEditorsShape, INotebookEditorPropertiesChangeData, INotebookEditorViewColumnInfo } from 'vs/workbench/api/common/extHost.protocol';
@ -13,8 +14,8 @@ import type * as vscode from 'vscode';
export class ExtHostNotebookEditors implements ExtHostNotebookEditorsShape {
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>();
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeNotebookEditorSelection = new Emitter<vscode.NotebookEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeNotebookEditorVisibleRanges = new Emitter<vscode.NotebookEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });
readonly onDidChangeNotebookEditorSelection = this._onDidChangeNotebookEditorSelection.event;
readonly onDidChangeNotebookEditorVisibleRanges = this._onDidChangeNotebookEditorVisibleRanges.event;

View file

@ -4,6 +4,7 @@
*--------------------------------------------------------------------------------------------*/
import * as arrays from 'vs/base/common/arrays';
import { onUnexpectedExternalError } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
@ -15,12 +16,12 @@ import * as vscode from 'vscode';
export class ExtHostEditors implements ExtHostEditorsShape {
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>();
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>();
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>();
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>();
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>();
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>();
private readonly _onDidChangeTextEditorSelection = new Emitter<vscode.TextEditorSelectionChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorOptions = new Emitter<vscode.TextEditorOptionsChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorVisibleRanges = new Emitter<vscode.TextEditorVisibleRangesChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeTextEditorViewColumn = new Emitter<vscode.TextEditorViewColumnChangeEvent>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeActiveTextEditor = new Emitter<vscode.TextEditor | undefined>({ onListenerError: onUnexpectedExternalError });
private readonly _onDidChangeVisibleTextEditors = new Emitter<readonly vscode.TextEditor[]>({ onListenerError: onUnexpectedExternalError });
readonly onDidChangeTextEditorSelection: Event<vscode.TextEditorSelectionChangeEvent> = this._onDidChangeTextEditorSelection.event;
readonly onDidChangeTextEditorOptions: Event<vscode.TextEditorOptionsChangeEvent> = this._onDidChangeTextEditorOptions.event;

View file

@ -7,7 +7,7 @@ import * as nativeWatchdog from 'native-watchdog';
import * as net from 'net';
import * as minimist from 'minimist';
import * as performance from 'vs/base/common/performance';
import type { MessagePortMain } from 'vs/base/parts/sandbox/node/electronTypes';
import type { UtilityNodeJSProcess, MessagePortMain } from 'vs/base/parts/sandbox/node/electronTypes';
import { isCancellationError, isSigPipeError, onUnexpectedError } from 'vs/base/common/errors';
import { Event } from 'vs/base/common/event';
import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc';
@ -132,7 +132,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
});
};
process.parentPort.on('message', (e: Electron.MessageEvent) => withPorts(e.ports));
(process as UtilityNodeJSProcess).parentPort.on('message', (e: Electron.MessageEvent) => withPorts(e.ports));
});
} else if (extHostConnection.type === ExtHostConnectionType.Socket) {

View file

@ -183,6 +183,7 @@ export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget {
EmbeddedCodeEditorWidget,
editorContainer,
editorOptions,
{},
this.editor
);

View file

@ -22,3 +22,4 @@ import './toggleRenderWhitespace';
import './toggleWordWrap';
import './untitledTextEditorHint/untitledTextEditorHint';
import './workbenchReferenceSearch';
import './editorLineNumberMenu';

View file

@ -0,0 +1,57 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Separator } from 'vs/base/common/actions';
import { Disposable } from 'vs/base/common/lifecycle';
import { ICodeEditor, MouseTargetType } from 'vs/editor/browser/editorBrowser';
import { registerEditorContribution, EditorContributionInstantiation } from 'vs/editor/browser/editorExtensions';
import { IEditorContribution } from 'vs/editor/common/editorCommon';
import { IMenuService, MenuId } from 'vs/platform/actions/common/actions';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { IBreakpointEditorContribution, BREAKPOINT_EDITOR_CONTRIBUTION_ID } from 'vs/workbench/contrib/debug/common/debug';
class EditorLineNumberContextMenu extends Disposable implements IEditorContribution {
private readonly menu = this._register(this.menuService.createMenu(MenuId.EditorLineNumberContext, this.contextKeyService));
constructor(
private readonly editor: ICodeEditor,
@IContextMenuService private readonly contextMenuService: IContextMenuService,
@IMenuService private readonly menuService: IMenuService,
@IContextKeyService private readonly contextKeyService: IContextKeyService,
) {
super();
this.registerListeners();
}
private registerListeners(): void {
this._register(this.editor.onContextMenu((e) => {
const model = this.editor.getModel();
if (!e.target.position || !model || e.target.type !== MouseTargetType.GUTTER_LINE_NUMBERS) {
return;
}
const anchor = { x: e.event.posx, y: e.event.posy };
const lineNumber = e.target.position.lineNumber;
const actions = Separator.join(...this.menu.getActions().map(a => a[1]));
// TODO@joyceerhl refactor breakpoint and testing actions to statically contribute to this menu
const contribution = this.editor.getContribution<IBreakpointEditorContribution>(BREAKPOINT_EDITOR_CONTRIBUTION_ID);
if (contribution) {
actions.push(...contribution.getContextMenuActionsAtPosition(lineNumber, model));
}
this.contextMenuService.showContextMenu({
getAnchor: () => anchor,
getActions: () => actions,
});
}));
}
}
registerEditorContribution('workbench.contrib.editorLineNumberContextMenu', EditorLineNumberContextMenu, EditorContributionInstantiation.AfterFirstRender);

View file

@ -58,7 +58,7 @@ function aLocalExtension(name: string = 'someext', manifest: any = {}, propertie
}
export class TestExperimentService extends ExperimentService {
public override getExperiments(): Promise<any[]> {
protected override getExperiments(): Promise<any[]> {
return Promise.resolve(experimentData.experiments);
}
}
@ -1194,5 +1194,3 @@ suite('Experiment Service', () => {
});

View file

@ -664,7 +664,7 @@ export class ExtensionsViewPaneContainer extends ViewPaneContainer implements IE
: '';
}
override saveState(): void {
protected override saveState(): void {
const value = this.searchBox ? this.searchBox.getValue() : '';
if (ExtensionsListView.isLocalExtensionsQuery(value)) {
this.searchViewletState['query.value'] = value;

View file

@ -41,6 +41,10 @@ const interactiveSessionExtensionPoint = extensionsRegistry.ExtensionsRegistry.r
description: localize('vscode.extension.contributes.interactiveSession.icon', "An icon for this Interactive Session provider."),
type: 'string'
},
when: {
description: localize('vscode.extension.contributes.interactiveSession.when', "A condition which must be true to enable this Interactive Session provider."),
type: 'string'
},
}
}
}

View file

@ -29,6 +29,7 @@ import { CollapsedCodeCellExecutionIcon } from 'vs/workbench/contrib/notebook/br
import { CodeCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/codeCellViewModel';
import { INotebookExecutionStateService } from 'vs/workbench/contrib/notebook/common/notebookExecutionStateService';
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
export class CodeCell extends Disposable {
private _outputContainerRenderer: CellOutputContainer;
@ -269,6 +270,13 @@ export class CodeCell extends Disposable {
this.notebookEditor.revealRangeInViewAsync(this.viewCell, lastSelection);
}
}));
this._register(this.templateData.editor.onDidBlurEditorWidget(() => {
WordHighlighterContribution.get(this.templateData.editor)?.stopHighlighting();
}));
this._register(this.templateData.editor.onDidFocusEditorWidget(() => {
WordHighlighterContribution.get(this.templateData.editor)?.restoreViewState(true);
}));
}
private _reigsterModelListeners(model: ITextModel) {

View file

@ -29,6 +29,7 @@ import { collapsedIcon, expandedIcon } from 'vs/workbench/contrib/notebook/brows
import { CellEditorOptions } from 'vs/workbench/contrib/notebook/browser/view/cellParts/cellEditorOptions';
import { MarkdownCellRenderTemplate } from 'vs/workbench/contrib/notebook/browser/view/notebookRenderingCommon';
import { MarkupCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markupCellViewModel';
import { WordHighlighterContribution } from 'vs/editor/contrib/wordHighlighter/browser/wordHighlighter';
export class MarkupCell extends Disposable {
@ -334,6 +335,16 @@ export class MarkupCell extends Disposable {
contributions: this.notebookEditor.creationOptions.cellEditorContributions
}));
this.templateData.currentEditor = this.editor;
this.editorDisposables.add(this.editor.onDidBlurEditorWidget(() => {
if (this.editor) {
WordHighlighterContribution.get(this.editor)?.stopHighlighting();
}
}));
this.editorDisposables.add(this.editor.onDidFocusEditorWidget(() => {
if (this.editor) {
WordHighlighterContribution.get(this.editor)?.restoreViewState(true);
}
}));
const cts = new CancellationTokenSource();
this.editorDisposables.add({ dispose() { cts.dispose(true); } });

View file

@ -78,7 +78,7 @@ function validateWebviewBoundary(element: HTMLElement) {
}
export class NotebookCellList extends WorkbenchList<CellViewModel> implements IDisposable, IStyleController, INotebookCellList {
override readonly view!: NotebookCellListView<CellViewModel>;
protected override readonly view!: NotebookCellListView<CellViewModel>;
get onWillScroll(): Event<ScrollEvent> { return this.view.onWillScroll; }
get rowsContainer(): HTMLElement {

View file

@ -408,6 +408,12 @@ export class RemoteStatusIndicator extends Disposable implements IWorkbenchContr
if (isCurrentRemote1 !== isCurrentRemote2) {
return isCurrentRemote1 ? -1 : 1;
}
// legacy indicator commands go last
if (g1[0] !== '' && g2[0] === '') {
return -1;
} else if (g1[0] === '' && g2[0] !== '') {
return 1;
}
return g1[0].localeCompare(g2[0]);
});
}

View file

@ -63,7 +63,7 @@ import { IQuickDiffSelectItem, SwitchQuickDiffBaseAction, SwitchQuickDiffViewIte
class DiffActionRunner extends ActionRunner {
override runAction(action: IAction, context: any): Promise<any> {
protected override runAction(action: IAction, context: any): Promise<any> {
if (action instanceof MenuItemAction) {
return action.run(...context);
}

View file

@ -370,7 +370,7 @@ class RepositoryPaneActionRunner extends ActionRunner {
super();
}
override async runAction(action: IAction, context: ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
protected override async runAction(action: IAction, context: ISCMResource | IResourceNode<ISCMResource, ISCMResourceGroup>): Promise<any> {
if (!(action instanceof MenuItemAction)) {
return super.runAction(action, context);
}

View file

@ -99,7 +99,7 @@ class StatusBarActionViewItem extends ActionViewItem {
super(null, action, {});
}
override updateLabel(): void {
protected override updateLabel(): void {
if (this.options.label && this.label) {
reset(this.label, ...renderLabelWithIcons(this.action.label));
}

View file

@ -1182,6 +1182,7 @@ class PlainTextMessagePeek extends Disposable implements IPeekOutputRenderer {
EmbeddedCodeEditorWidget,
this.container,
commonEditorOptions,
{},
this.editor,
) : this.instantiationService.createInstance(
CodeEditorWidget,

View file

@ -1090,7 +1090,7 @@ export class TimelineIdentityProvider implements IIdentityProvider<TreeElement>
class TimelineActionRunner extends ActionRunner {
override async runAction(action: IAction, { uri, item }: TimelineActionContext): Promise<void> {
protected override async runAction(action: IAction, { uri, item }: TimelineActionContext): Promise<void> {
if (!isTimelineItem(item)) {
// TODO@eamodio do we need to do anything else?
await action.run();

View file

@ -184,6 +184,7 @@ export class TypeHierarchyTreePeekWidget extends peekView.PeekViewWidget {
EmbeddedCodeEditorWidget,
editorContainer,
editorOptions,
{},
this.editor
);

View file

@ -0,0 +1,200 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Disposable } from 'vs/base/common/lifecycle';
import { IExtensionGalleryService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IProductService } from 'vs/platform/product/common/productService';
import { IFeaturedExtension } from 'vs/base/common/product';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage';
import { localize } from 'vs/nls';
import { IWorkbenchAssignmentService } from 'vs/workbench/services/assignment/common/assignmentService';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
type FeaturedExtensionTreatment = { extensions: string[]; showAsList?: string };
type FeaturedExtensionStorageData = { title: string; description: string; imagePath: string; date: number };
export const IFeaturedExtensionsService = createDecorator<IFeaturedExtensionsService>('featuredExtensionsService');
export interface IFeaturedExtensionsService {
_serviceBrand: undefined;
getExtensions(): Promise<IFeaturedExtension[]>;
title: string;
}
const enum FeaturedExtensionMetadataType {
Title,
Description,
ImagePath
}
export class FeaturedExtensionsService extends Disposable implements IFeaturedExtensionsService {
declare readonly _serviceBrand: undefined;
private ignoredExtensions: Set<string> = new Set<string>();
private treatment: FeaturedExtensionTreatment | undefined;
private _isInitialized: boolean = false;
private static readonly STORAGE_KEY = 'workbench.welcomePage.extensionMetadata';
constructor(
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService,
@IWorkbenchAssignmentService private readonly tasExperimentService: IWorkbenchAssignmentService,
@IStorageService private readonly storageService: IStorageService,
@IProductService private readonly productService: IProductService,
@IExtensionGalleryService private readonly galleryService: IExtensionGalleryService,
) {
super();
this.title = localize('gettingStarted.featuredTitle', 'Featured');
}
title: string;
async getExtensions(): Promise<IFeaturedExtension[]> {
await this._init();
let treatments = this.treatment?.extensions.filter(extension => !this.ignoredExtensions.has(extension)) ?? new Array<string>();
const featuredExtensions: IFeaturedExtension[] = new Array();
if (this.treatment?.showAsList !== 'true' && treatments.length > 0) {
// pick a random extensionId for display
const treatment = treatments[Math.floor(Math.random() * treatments.length)];
treatments = [treatment];
}
for (const treatment of treatments) {
const extension = await this.resolveExtension(treatment);
if (extension) {
featuredExtensions.push(extension);
}
}
return featuredExtensions;
}
private async _init(): Promise<void> {
if (this._isInitialized) {
return;
}
const extensions = await Promise.race([
this.tasExperimentService?.getTreatment<string>('welcome.featured.item'),
new Promise<string | undefined>(resolve => setTimeout(() => resolve(''), 2000))
]);
const extensionListTitle = await Promise.race([
this.tasExperimentService?.getTreatment<string>('welcome.featured.title'),
new Promise<string | undefined>(resolve => setTimeout(() => resolve(''), 2000))
]);
this.treatment = extensions ? JSON.parse(extensions) : { extensions: [] };
this.title = extensionListTitle ?? localize('gettingStarted.featuredTitle', 'Featured');
if (this.treatment) {
const installed = await this.extensionManagementService.getInstalled();
for (const extension of this.treatment.extensions) {
if (installed.some(e => ExtensionIdentifier.equals(e.identifier.id, extension))) {
this.ignoredExtensions.add(extension);
}
}
}
this._isInitialized = true;
}
private async resolveExtension(extensionId: string): Promise<IFeaturedExtension | undefined> {
const productMetadata = this.productService.featuredExtensions?.find(e => ExtensionIdentifier.equals(e.id, extensionId));
const title = productMetadata?.title ?? await this.getMetadata(extensionId, FeaturedExtensionMetadataType.Title);
const description = productMetadata?.description ?? await this.getMetadata(extensionId, FeaturedExtensionMetadataType.Description);
const imagePath = productMetadata?.imagePath ?? await this.getMetadata(extensionId, FeaturedExtensionMetadataType.ImagePath);
if (title && description && imagePath) {
return {
id: extensionId,
title: title,
description: description,
imagePath: imagePath,
};
}
return undefined;
}
private async getMetadata(extensionId: string, key: FeaturedExtensionMetadataType): Promise<string | undefined> {
const storageMetadata = this.getStorageData(extensionId);
if (storageMetadata) {
switch (key) {
case FeaturedExtensionMetadataType.Title: {
return storageMetadata.title;
}
case FeaturedExtensionMetadataType.Description: {
return storageMetadata.description;
}
case FeaturedExtensionMetadataType.ImagePath: {
return storageMetadata.imagePath;
}
default:
return undefined;
}
}
return await this.getGalleryMetadata(extensionId, key);
}
private getStorageData(extensionId: string): FeaturedExtensionStorageData | undefined {
const metadata = this.storageService.get(FeaturedExtensionsService.STORAGE_KEY + '.' + extensionId, StorageScope.APPLICATION);
if (metadata) {
const value = JSON.parse(metadata) as FeaturedExtensionStorageData;
const lastUpdateDate = new Date().getTime() - value.date;
if (lastUpdateDate < 1000 * 60 * 60 * 24 * 7) {
return value;
}
}
return undefined;
}
private async getGalleryMetadata(extensionId: string, key: FeaturedExtensionMetadataType): Promise<string | undefined> {
const storageKey = FeaturedExtensionsService.STORAGE_KEY + '.' + extensionId;
this.storageService.remove(storageKey, StorageScope.APPLICATION);
const galleryExtension = (await this.galleryService.getExtensions([{ id: extensionId }], CancellationToken.None))[0];
let metadata: string | undefined;
if (galleryExtension) {
switch (key) {
case FeaturedExtensionMetadataType.Title: {
metadata = galleryExtension.displayName;
break;
}
case FeaturedExtensionMetadataType.Description: {
metadata = galleryExtension.description;
break;
}
case FeaturedExtensionMetadataType.ImagePath: {
metadata = galleryExtension.assets.icon?.uri;
break;
}
}
this.storageService.store(storageKey, JSON.stringify({
title: galleryExtension.displayName,
description: galleryExtension.description,
imagePath: galleryExtension.assets.icon?.uri,
date: new Date().getTime()
}), StorageScope.APPLICATION, StorageTarget.MACHINE);
}
return metadata;
}
}
registerSingleton(IFeaturedExtensionsService, FeaturedExtensionsService, InstantiationType.Delayed);

View file

@ -70,6 +70,10 @@ import { GettingStartedDetailsRenderer } from 'vs/workbench/contrib/welcomeGetti
import { IAccessibilityService } from 'vs/platform/accessibility/common/accessibility';
import { renderLabelWithIcons } from 'vs/base/browser/ui/iconLabel/iconLabels';
import { defaultButtonStyles, defaultToggleStyles } from 'vs/platform/theme/browser/defaultStyles';
import { IFeaturedExtensionsService } from 'vs/workbench/contrib/welcomeGettingStarted/browser/featuredExtensionService';
import { IFeaturedExtension } from 'vs/base/common/product';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions';
const SLIDE_TRANSITION_TIME_MS = 250;
const configurationKey = 'workbench.startupEditor';
@ -98,6 +102,13 @@ const parsedStartEntries: IWelcomePageStartEntry[] = startEntries.map((e, i) =>
when: ContextKeyExpr.deserialize(e.when) ?? ContextKeyExpr.true()
}));
type GettingStartedLayoutEventClassification = {
owner: 'bhavyau';
comment: 'Information about the layout of the welcome page';
featuredExtensions: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'visible featured extensions' };
title: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'featured extension title' };
};
type GettingStartedActionClassification = {
command: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The command being executed on the getting started page.' };
walkthroughId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'The walkthrough which the command is in' };
@ -127,6 +138,8 @@ export class GettingStartedPage extends EditorPane {
private detailsPageDisposables: DisposableStore = new DisposableStore();
private gettingStartedCategories: IResolvedWalkthrough[];
private featuredExtensions?: Promise<IFeaturedExtension[]>;
private currentWalkthrough: IResolvedWalkthrough | undefined;
private categoriesPageScrollbar: DomScrollableElement | undefined;
@ -145,6 +158,7 @@ export class GettingStartedPage extends EditorPane {
private recentlyOpenedList?: GettingStartedIndexList<RecentEntry>;
private startList?: GettingStartedIndexList<IWelcomePageStartEntry>;
private gettingStartedList?: GettingStartedIndexList<IResolvedWalkthrough>;
private featuredExtensionsList?: GettingStartedIndexList<IFeaturedExtension>;
private stepsSlide!: HTMLElement;
private categoriesSlide!: HTMLElement;
@ -162,6 +176,7 @@ export class GettingStartedPage extends EditorPane {
@IProductService private readonly productService: IProductService,
@IKeybindingService private readonly keybindingService: IKeybindingService,
@IWalkthroughsService private readonly gettingStartedService: IWalkthroughsService,
@IFeaturedExtensionsService private readonly featuredExtensionService: IFeaturedExtensionsService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ITelemetryService telemetryService: ITelemetryService,
@ILanguageService private readonly languageService: ILanguageService,
@ -181,6 +196,7 @@ export class GettingStartedPage extends EditorPane {
@IWebviewService private readonly webviewService: IWebviewService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IAccessibilityService private readonly accessibilityService: IAccessibilityService,
@IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService
) {
super(GettingStartedPage.ID, telemetryService, themeService, storageService);
@ -203,11 +219,15 @@ export class GettingStartedPage extends EditorPane {
embedderIdentifierContext.bindTo(this.contextService).set(productService.embedderIdentifier);
this.gettingStartedCategories = this.gettingStartedService.getWalkthroughs();
this.featuredExtensions = this.featuredExtensionService.getExtensions();
this._register(this.dispatchListeners);
this.buildSlideThrottle = new Throttler();
const rerender = () => {
this.gettingStartedCategories = this.gettingStartedService.getWalkthroughs();
this.featuredExtensions = this.featuredExtensionService.getExtensions();
if (this.currentWalkthrough) {
const existingSteps = this.currentWalkthrough.steps.map(step => step.id);
const newCategory = this.gettingStartedCategories.find(category => this.currentWalkthrough?.id === category.id);
@ -222,6 +242,15 @@ export class GettingStartedPage extends EditorPane {
}
};
this._register(this.extensionManagementService.onDidInstallExtensions(async (result) => {
for (const e of result) {
const installedFeaturedExtension = (await this.featuredExtensions)?.find(ext => ExtensionIdentifier.equals(ext.id, e.identifier.id));
if (installedFeaturedExtension) {
this.hideExtension(e.identifier.id);
}
}
}));
this._register(this.gettingStartedService.onDidAddWalkthrough(rerender));
this._register(this.gettingStartedService.onDidRemoveWalkthrough(rerender));
@ -420,6 +449,14 @@ export class GettingStartedPage extends EditorPane {
}
break;
}
case 'openExtensionPage': {
this.commandService.executeCommand('extension.open', argument);
break;
}
case 'hideExtension': {
this.hideExtension(argument);
break;
}
default: {
console.error('Dispatch to', command, argument, 'not defined');
break;
@ -434,6 +471,12 @@ export class GettingStartedPage extends EditorPane {
this.gettingStartedList?.rerender();
}
private hideExtension(extensionId: string) {
this.setHiddenCategories([...this.getHiddenCategories().add(extensionId)]);
this.featuredExtensionsList?.rerender();
this.registerDispatchListeners();
}
private markAllStepsComplete() {
if (this.currentWalkthrough) {
this.currentWalkthrough?.steps.forEach(step => {
@ -721,7 +764,6 @@ export class GettingStartedPage extends EditorPane {
this.categoriesPageScrollbar.scanDomNode();
this.detailsPageScrollbar.scanDomNode();
parent.appendChild(this.container);
}
@ -759,12 +801,12 @@ export class GettingStartedPage extends EditorPane {
$('p.subtitle.description', {}, localize({ key: 'gettingStarted.editingEvolved', comment: ['Shown as subtitle on the Welcome page.'] }, "Editing evolved"))
);
const leftColumn = $('.categories-column.categories-column-left', {},);
const rightColumn = $('.categories-column.categories-column-right', {},);
const startList = this.buildStartList();
const recentList = this.buildRecentlyOpenedList();
const featuredExtensionList = this.buildFeaturedExtensionsList();
const gettingStartedList = this.buildGettingStartedWalkthroughsList();
const footer = $('.footer', {},
@ -777,18 +819,36 @@ export class GettingStartedPage extends EditorPane {
if (gettingStartedList.itemCount) {
this.container.classList.remove('noWalkthroughs');
reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
reset(rightColumn, gettingStartedList.getDomElement());
reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
recentList.setLimit(5);
}
else {
this.container.classList.add('noWalkthroughs');
reset(leftColumn, startList.getDomElement());
reset(rightColumn, recentList.getDomElement());
reset(rightColumn, recentList.getDomElement(), featuredExtensionList.getDomElement());
recentList.setLimit(10);
}
setTimeout(() => this.categoriesPageScrollbar?.scanDomNode(), 50);
};
const layoutFeaturedExtension = () => {
if (featuredExtensionList.itemCount) {
this.container.classList.remove('noExtensions');
reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
reset(rightColumn, featuredExtensionList.getDomElement(), gettingStartedList.getDomElement());
recentList.setLimit(5);
}
else {
this.container.classList.add('noExtensions');
reset(leftColumn, startList.getDomElement(), recentList.getDomElement());
reset(rightColumn, gettingStartedList.getDomElement());
recentList.setLimit(10);
}
setTimeout(() => this.categoriesPageScrollbar?.scanDomNode(), 50);
};
featuredExtensionList.onDidChange(layoutFeaturedExtension);
layoutFeaturedExtension();
gettingStartedList.onDidChange(layoutLists);
layoutLists();
@ -1041,10 +1101,65 @@ export class GettingStartedPage extends EditorPane {
gettingStartedList.setEntries(this.gettingStartedCategories);
allWalkthroughsHiddenContext.bindTo(this.contextService).set(gettingStartedList.itemCount === 0);
return gettingStartedList;
}
private buildFeaturedExtensionsList(): GettingStartedIndexList<IFeaturedExtension> {
const renderFeaturedExtensions = (entry: IFeaturedExtension): HTMLElement => {
const descriptionContent = $('.featured-description-content', {},);
reset(descriptionContent, ...renderLabelWithIcons(entry.description));
const titleContent = $('h3.category-title.max-lines-3', { 'x-category-title-for': entry.id });
reset(titleContent, ...renderLabelWithIcons(entry.title));
return $('button.getting-started-category',
{
'x-dispatch': 'openExtensionPage:' + entry.id,
'title': entry.description
},
$('.main-content', {},
$('img.featured-icon.icon-widget', { src: entry.imagePath }),
titleContent,
$('a.codicon.codicon-close.hide-category-button', {
'tabindex': 0,
'x-dispatch': 'hideExtension:' + entry.id,
'title': localize('close', "Hide"),
'role': 'button',
'aria-label': localize('closeAriaLabel', "Hide"),
}),
),
descriptionContent);
};
if (this.featuredExtensionsList) {
this.featuredExtensionsList.dispose();
}
const featuredExtensionsList = this.featuredExtensionsList = new GettingStartedIndexList(
{
title: this.featuredExtensionService.title,
klass: 'featured-extensions',
limit: 5,
renderElement: renderFeaturedExtensions,
rankElement: (extension) => { if (this.getHiddenCategories().has(extension.id)) { return null; } return 0; },
contextService: this.contextService,
});
this.featuredExtensions?.then(extensions => {
this.telemetryService.publicLog2<{ featuredExtensions: string[]; title: string }, GettingStartedLayoutEventClassification>('gettingStarted.layout', { featuredExtensions: extensions.map(e => e.id), title: this.featuredExtensionService.title });
featuredExtensionsList.setEntries(extensions);
});
this.featuredExtensionsList?.onDidChange(() => {
this.registerDispatchListeners();
});
return featuredExtensionsList;
}
layout(size: Dimension) {
this.detailsScrollbar?.scanDomNode();
@ -1053,6 +1168,7 @@ export class GettingStartedPage extends EditorPane {
this.startList?.layout(size);
this.gettingStartedList?.layout(size);
this.featuredExtensionsList?.layout(size);
this.recentlyOpenedList?.layout(size);
this.layoutMarkdown?.();
@ -1077,7 +1193,6 @@ export class GettingStartedPage extends EditorPane {
const progress = (stats.stepsComplete / stats.stepsTotal) * 100;
bar.style.width = `${progress}%`;
(element.parentElement as HTMLElement).classList.toggle('no-progress', stats.stepsComplete === 0);
if (stats.stepsTotal === stats.stepsComplete) {
@ -1239,7 +1354,9 @@ export class GettingStartedPage extends EditorPane {
this.detailsPageDisposables.clear();
const category = this.gettingStartedCategories.find(category => category.id === categoryID);
if (!category) { throw Error('could not find category with ID ' + categoryID); }
if (!category) {
throw Error('could not find category with ID ' + categoryID);
}
const categoryDescriptorComponent =
$('.getting-started-category',
@ -1275,6 +1392,8 @@ export class GettingStartedPage extends EditorPane {
const contextKeysToWatch = new Set(category.steps.flatMap(step => step.when.keys()));
const buildStepList = () => {
category.steps.sort((a, b) => a.order - b.order);
const toRender = category.steps
.filter(step => this.contextService.contextMatchesRules(step.when));

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