mirror of
https://github.com/Microsoft/vscode
synced 2024-11-05 18:29:38 +00:00
Merge branch 'main' into tyriar/links_contrib
This commit is contained in:
commit
ade8346118
108 changed files with 2761 additions and 468 deletions
5
.github/classifier.json
vendored
5
.github/classifier.json
vendored
|
@ -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
2
.nvmrc
|
@ -1 +1 @@
|
|||
16.17
|
||||
16.14
|
||||
|
|
2
.yarnrc
2
.yarnrc
|
@ -1,4 +1,4 @@
|
|||
disturl "https://electronjs.org/headers"
|
||||
target "22.3.1"
|
||||
target "19.1.9"
|
||||
runtime "electron"
|
||||
build_from_source "true"
|
||||
|
|
|
@ -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++)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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}`;
|
||||
|
|
|
@ -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
|
@ -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
|
@ -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);
|
||||
|
|
|
@ -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=
|
|
@ -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',
|
||||
|
|
|
@ -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
|
|
@ -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
|
@ -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)',
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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": {
|
||||
|
|
|
@ -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`);
|
||||
|
||||
|
|
|
@ -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",
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
disturl "http://nodejs.org/dist"
|
||||
target "16.17.1"
|
||||
target "16.14.2"
|
||||
runtime "node"
|
||||
build_from_source "true"
|
||||
|
|
|
@ -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"
|
||||
|
|
23
src/main.js
23
src/main.js
|
@ -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);
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 20;
|
||||
z-index: 5;
|
||||
pointer-events: none;
|
||||
background-color: var(--separator-border);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
});
|
||||
|
|
137
src/vs/base/parts/sandbox/electron-main/electronTypes.ts
Normal file
137
src/vs/base/parts/sandbox/electron-main/electronTypes.ts
Normal 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');
|
|
@ -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) => () => {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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[] {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -92,7 +92,7 @@ export abstract class SymbolNavigationAction extends EditorAction2 {
|
|||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
return <typeof opts>result;
|
||||
}
|
||||
|
||||
readonly configuration: SymbolNavigationActionConfig;
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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);
|
124
src/vs/editor/contrib/interactive/browser/interactiveEditor.css
Normal file
124
src/vs/editor/contrib/interactive/browser/interactiveEditor.css
Normal 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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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"));
|
|
@ -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];
|
||||
}
|
||||
}
|
|
@ -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.'));
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
1
src/vs/monaco.d.ts
vendored
|
@ -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.
|
||||
|
|
|
@ -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> {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 }]));
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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[][] {
|
||||
|
|
|
@ -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>;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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()
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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]);
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -70,6 +70,7 @@ import './mainThreadNotebookKernels';
|
|||
import './mainThreadNotebookDocumentsAndEditors';
|
||||
import './mainThreadNotebookRenderers';
|
||||
import './mainThreadInteractive';
|
||||
import './mainThreadInteractiveEditor';
|
||||
import './mainThreadInteractiveSession';
|
||||
import './mainThreadTask';
|
||||
import './mainThreadLabelService';
|
||||
|
|
54
src/vs/workbench/api/browser/mainThreadInteractiveEditor.ts
Normal file
54
src/vs/workbench/api/browser/mainThreadInteractiveEditor.ts
Normal 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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
|
@ -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'),
|
||||
|
|
111
src/vs/workbench/api/common/extHostInteractiveEditor.ts
Normal file
111
src/vs/workbench/api/common/extHostInteractiveEditor.ts
Normal 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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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');
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -183,6 +183,7 @@ export class CallHierarchyTreePeekWidget extends peekView.PeekViewWidget {
|
|||
EmbeddedCodeEditorWidget,
|
||||
editorContainer,
|
||||
editorOptions,
|
||||
{},
|
||||
this.editor
|
||||
);
|
||||
|
||||
|
|
|
@ -22,3 +22,4 @@ import './toggleRenderWhitespace';
|
|||
import './toggleWordWrap';
|
||||
import './untitledTextEditorHint/untitledTextEditorHint';
|
||||
import './workbenchReferenceSearch';
|
||||
import './editorLineNumberMenu';
|
||||
|
|
|
@ -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);
|
|
@ -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', () => {
|
|||
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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'
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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); } });
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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]);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
|
@ -1182,6 +1182,7 @@ class PlainTextMessagePeek extends Disposable implements IPeekOutputRenderer {
|
|||
EmbeddedCodeEditorWidget,
|
||||
this.container,
|
||||
commonEditorOptions,
|
||||
{},
|
||||
this.editor,
|
||||
) : this.instantiationService.createInstance(
|
||||
CodeEditorWidget,
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -184,6 +184,7 @@ export class TypeHierarchyTreePeekWidget extends peekView.PeekViewWidget {
|
|||
EmbeddedCodeEditorWidget,
|
||||
editorContainer,
|
||||
editorOptions,
|
||||
{},
|
||||
this.editor
|
||||
);
|
||||
|
||||
|
|
|
@ -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);
|
|
@ -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
Loading…
Reference in a new issue