mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-08 17:19:48 +01:00
Merge branch 'main' into tyriar/183423
This commit is contained in:
+1
-1
@@ -7,7 +7,7 @@
|
||||
{
|
||||
"kind": 2,
|
||||
"language": "github-issues",
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice\n\n// current milestone name\n$milestone=milestone:\"June 2023\""
|
||||
"value": "// list of repos we work in\n$repos=repo:microsoft/vscode repo:microsoft/vscode-remote-release repo:microsoft/vscode-js-debug repo:microsoft/vscode-pull-request-github repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-internalbacklog repo:microsoft/vscode-dev repo:microsoft/vscode-unpkg repo:microsoft/vscode-references-view repo:microsoft/vscode-anycode repo:microsoft/vscode-hexeditor repo:microsoft/vscode-extension-telemetry repo:microsoft/vscode-livepreview repo:microsoft/vscode-remotehub repo:microsoft/vscode-settings-sync-server repo:microsoft/vscode-remote-repositories-github repo:microsoft/monaco-editor repo:microsoft/vscode-vsce repo:microsoft/vscode-dev-chrome-launcher repo:microsoft/vscode-emmet-helper repo:microsoft/vscode-python repo:microsoft/vscode-jupyter repo:microsoft/vscode-jupyter-internal repo:microsoft/vscode-github-issue-notebooks repo:microsoft/vscode-l10n repo:microsoft/vscode-remote-tunnels repo:microsoft/vscode-markdown-tm-grammar repo:microsoft/vscode-markdown-languageservice repo:microsoft/vscode-copilot repo:microsoft/vscode-copilot-release\n\n// current milestone name\n$milestone=milestone:\"June 2023\""
|
||||
},
|
||||
{
|
||||
"kind": 1,
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
2023-03-31T12:39:03.753Z
|
||||
2023-06-12T12:55:48.130Z
|
||||
|
||||
@@ -37,6 +37,8 @@ fsevents/test/**
|
||||
@vscode/windows-process-tree/binding.gyp
|
||||
@vscode/windows-process-tree/build/**
|
||||
@vscode/windows-process-tree/src/**
|
||||
@vscode/windows-process-tree/tsconfig.json
|
||||
@vscode/windows-process-tree/tslint.json
|
||||
!@vscode/windows-process-tree/**/*.node
|
||||
|
||||
@vscode/windows-registry/binding.gyp
|
||||
|
||||
@@ -1,4 +1,17 @@
|
||||
@vscode/windows-mutex/index.js
|
||||
@vscode/windows-mutex/**/*.node
|
||||
@vscode/windows-mutex/*.md
|
||||
@vscode/windows-mutex/package.json
|
||||
@vscode/windows-mutex/package.json
|
||||
|
||||
@vscode/windows-process-tree/lib/**
|
||||
@vscode/windows-process-tree/**/*.node
|
||||
@vscode/windows-process-tree/LICENSE
|
||||
@vscode/windows-process-tree/package.json
|
||||
@vscode/windows-process-tree/*.md
|
||||
|
||||
@vscode/windows-registry/dist/**
|
||||
@vscode/windows-registry/**/*.node
|
||||
@vscode/windows-registry/*.md
|
||||
@vscode/windows-registry/*.txt
|
||||
@vscode/windows-registry/package.json
|
||||
!@vscode/windows-registry/dist/index.d.ts
|
||||
@@ -1,4 +1,17 @@
|
||||
@vscode/windows-mutex/index.js
|
||||
@vscode/windows-mutex/**/*.node
|
||||
@vscode/windows-mutex/*.md
|
||||
@vscode/windows-mutex/package.json
|
||||
@vscode/windows-mutex/package.json
|
||||
|
||||
@vscode/windows-process-tree/lib/**
|
||||
@vscode/windows-process-tree/**/*.node
|
||||
@vscode/windows-process-tree/LICENSE
|
||||
@vscode/windows-process-tree/package.json
|
||||
@vscode/windows-process-tree/*.md
|
||||
|
||||
@vscode/windows-registry/dist/**
|
||||
@vscode/windows-registry/**/*.node
|
||||
@vscode/windows-registry/*.md
|
||||
@vscode/windows-registry/*.txt
|
||||
@vscode/windows-registry/package.json
|
||||
!@vscode/windows-registry/dist/index.d.ts
|
||||
@@ -86,16 +86,10 @@ steps:
|
||||
# TODO@joaomoreno TODO@deepak1556 this should be part of the base image
|
||||
- ${{ if ne(parameters.VSCODE_QUALITY, 'oss') }}:
|
||||
- script: |
|
||||
if [ "$VSCODE_ARCH" = "x64" ]; then
|
||||
OS=ubuntu
|
||||
else
|
||||
OS=debian
|
||||
fi
|
||||
|
||||
sudo apt-get update && sudo apt-get install -y ca-certificates curl gnupg
|
||||
sudo mkdir -m 0755 -p /etc/apt/keyrings
|
||||
curl -fsSL https://download.docker.com/linux/$OS/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/$OS "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
|
||||
echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
|
||||
sudo apt update && sudo apt install -y docker-ce-cli
|
||||
displayName: Install Docker client
|
||||
condition: and(succeeded(), ne(variables.NODE_MODULES_RESTORED, 'true'))
|
||||
|
||||
@@ -144,11 +144,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:bionic-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:bionic-armhf
|
||||
endpoint: VSCodeHub
|
||||
options: --user 0:0 --cap-add SYS_ADMIN
|
||||
- container: snapcraft
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
dfb37570ef34ac04f34c26d0ec558df60a9665df5961c01c1657c0ca495f2f01 node-v16.17.1-aix-ppc64.tar.gz
|
||||
f9f02f7872e2e8ee54320fce13deb9d56904f32bb0615b6e21aa3371d8899150 node-v16.17.1-darwin-arm64.tar.gz
|
||||
09a45f60bfb9dfbea4f69044dc733ef983945acd92ca89ccccac267f3d71bd44 node-v16.17.1-darwin-arm64.tar.xz
|
||||
3db26761ad8493b894d42260d7e65094b7af9bc473588739e61bc1c32d6ff955 node-v16.17.1-darwin-x64.tar.gz
|
||||
8e7089956fa01cf7d0045945c0863d282dc6818fb0476237c1396497e29a4254 node-v16.17.1-darwin-x64.tar.xz
|
||||
35ccb95caf02cda3bd680da4350a8ae5d666a7a9eae3afe5c2a1b3ef29aef108 node-v16.17.1-headers.tar.gz
|
||||
554c8d1b4b16e0f4c073b9df7c49c893716a3a533f25ac646f23619f5ccee7df node-v16.17.1-headers.tar.xz
|
||||
adc7032888d4e672a4aac886baede8c04fccdd1a2e7ab4bcf325e3f336f44a3d node-v16.17.1-linux-arm64.tar.gz
|
||||
3dfb8fd8f6b97df69cdc56524abc906c50ef1d0bf091188616802e6c7c731389 node-v16.17.1-linux-arm64.tar.xz
|
||||
aeab05e35f1d2824ecfb88ca321f1408b44d292b2775f2890972c828e00216d0 node-v16.17.1-linux-armv7l.tar.gz
|
||||
a035ceefb5e16f5fce98c8ddfdf721b96eec20542c72fb8781bcbb6ef20c5550 node-v16.17.1-linux-armv7l.tar.xz
|
||||
1f48de7bed99e973c4c50f1b7fc99fc9af5144d093fd6d2b50a1e43b5818bf05 node-v16.17.1-linux-ppc64le.tar.gz
|
||||
70305934661f89fca64053b85317a75f233d5e3fdb2caa6546a19262a519cf20 node-v16.17.1-linux-ppc64le.tar.xz
|
||||
029dad48018bda07b481213816549b632059fc673c30fdc7a353e04619128344 node-v16.17.1-linux-s390x.tar.gz
|
||||
1a47f604944c6aff37cb7483503155671cdb34bda9bfb8962007bc440fa04d77 node-v16.17.1-linux-s390x.tar.xz
|
||||
da5658693243b3ecf6a4cba6751a71df1eb9e9703ca93b42a9404aed85f58ad0 node-v16.17.1-linux-x64.tar.gz
|
||||
06ba2eb34aa385967f5f58c87a44753f83212f6cccea892b33f80a2e7fda8384 node-v16.17.1-linux-x64.tar.xz
|
||||
12d10476ea7483298364c810c037b9316d1a73dc8c81cfeff7d794aecadde498 node-v16.17.1.pkg
|
||||
e423985f6019b2026f9a191adb56a96ae83ecd56cdf839cf94aa980168b7a90f node-v16.17.1.tar.gz
|
||||
6721feb4152d56d2c6b358ce397abd5a7f1daf09ee2e25c5021b9b4d3f86a330 node-v16.17.1.tar.xz
|
||||
9777e8c4b2864c5b54a0e4e9400f14887db68560a09b94b4113b560a64d1e680 node-v16.17.1-win-x64.7z
|
||||
ed290151efb417262b9808a70738d4ab79e9d53653a6a9f4b8dd97912e279dce node-v16.17.1-win-x64.zip
|
||||
0f8101648d5c9e49e89fee541da9e574f899716c32b7c51a732b1766b9fc4526 node-v16.17.1-win-x86.7z
|
||||
189b5e8b23226403e7b07a46614de19b444d369e694901e3668e2f549799cbcd node-v16.17.1-win-x86.zip
|
||||
1bdff65fb7642425c0d6826084d63c4be43520316f0ea0b46e6a51999a0ed7fc node-v16.17.1-x64.msi
|
||||
b737eb23a2c67c253b9364b5284123faf5220d567615bebd4ec4b81070e4d177 node-v16.17.1-x86.msi
|
||||
f518a70dcab7c3fac5b2e1ef100b4f628edfb160f4fafa9a94ef222da8a6e9ab win-x64/node.exe
|
||||
2f459a64647db493da63c790ce368ad54f59f086d9f22f59c5018680420197b3 win-x64/node.lib
|
||||
23215ce7d1e9de9777c3407239e7cf18d29d60f757b772219421ab361ac67c74 win-x64/node_pdb.7z
|
||||
8e32ec12028fd3e3147435be79a858ed9c870aaafa1fcb291362307ef3c47547 win-x64/node_pdb.zip
|
||||
2393aff88be19dbe0205cbde4ff0c1d89911b15de5c99c80f6e5e29604eecd12 win-x86/node.exe
|
||||
5018c3d42f3fbacbd06cb943b3f2696c8e67ca9bdf6864d0e263d6d6911dffd2 win-x86/node.lib
|
||||
05a4db56444a60ee70b0d2642d7f2d82a33339894d2d73bd07b1a41d6c869e04 win-x86/node_pdb.7z
|
||||
8f86eacb7f13a1bf6738cb0819d7854a2abca40fc2e9e1f91421e44ba52cad7e win-x86/node_pdb.zip
|
||||
+72
-30
@@ -17,7 +17,6 @@ const rename = require('gulp-rename');
|
||||
const replace = require('gulp-replace');
|
||||
const filter = require('gulp-filter');
|
||||
const { getProductionDependencies } = require('./lib/dependencies');
|
||||
const { assetFromGithub } = require('./lib/github');
|
||||
const vfs = require('vinyl-fs');
|
||||
const packageJson = require('../package.json');
|
||||
const flatmap = require('gulp-flatmap');
|
||||
@@ -43,7 +42,6 @@ const BUILD_TARGETS = [
|
||||
{ platform: 'win32', arch: 'x64' },
|
||||
{ platform: 'darwin', arch: 'x64' },
|
||||
{ platform: 'darwin', arch: 'arm64' },
|
||||
{ platform: 'linux', arch: 'ia32' },
|
||||
{ platform: 'linux', arch: 'x64' },
|
||||
{ platform: 'linux', arch: 'armhf' },
|
||||
{ platform: 'linux', arch: 'arm64' },
|
||||
@@ -131,6 +129,33 @@ function getNodeVersion() {
|
||||
return target;
|
||||
}
|
||||
|
||||
function getNodeChecksum(nodeVersion, platform, arch) {
|
||||
let expectedName;
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
expectedName = `win-${arch}/node.exe`;
|
||||
break;
|
||||
|
||||
case 'darwin':
|
||||
case 'linux':
|
||||
expectedName = `node-v${nodeVersion}-${platform}-${arch}.tar.gz`;
|
||||
break;
|
||||
|
||||
case 'alpine':
|
||||
expectedName = `${platform}-${arch}/node`;
|
||||
break;
|
||||
}
|
||||
|
||||
const nodeJsChecksums = fs.readFileSync(path.join(REPO_ROOT, 'build', 'checksums', 'nodejs.txt'), 'utf8');
|
||||
for (const line of nodeJsChecksums.split('\n')) {
|
||||
const [checksum, name] = line.split(/\s+/);
|
||||
if (name === expectedName) {
|
||||
return checksum;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const nodeVersion = getNodeVersion();
|
||||
|
||||
BUILD_TARGETS.forEach(({ platform, arch }) => {
|
||||
@@ -155,40 +180,57 @@ if (defaultNodeTask) {
|
||||
}
|
||||
|
||||
function nodejs(platform, arch) {
|
||||
const { remote } = require('./lib/gulpRemoteSource');
|
||||
const { fetchUrls, fetchGithub } = require('./lib/fetch');
|
||||
const untar = require('gulp-untar');
|
||||
const crypto = require('crypto');
|
||||
|
||||
if (arch === 'ia32') {
|
||||
arch = 'x86';
|
||||
}
|
||||
|
||||
if (platform === 'win32') {
|
||||
if (product.nodejsRepository) {
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejsRepository}...`);
|
||||
return assetFromGithub(product.nodejsRepository, nodeVersion, name => name === `win-${arch}-node.exe`)
|
||||
.pipe(rename('node.exe'));
|
||||
}
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from https://nodejs.org`);
|
||||
return remote(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', verbose: true })
|
||||
.pipe(rename('node.exe'));
|
||||
}
|
||||
|
||||
if (arch === 'alpine' || platform === 'alpine') {
|
||||
const imageName = arch === 'arm64' ? 'arm64v8/node' : 'node';
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from docker image ${imageName}`);
|
||||
const contents = cp.execSync(`docker run --rm ${imageName}:${nodeVersion}-alpine /bin/sh -c 'cat \`which node\`'`, { maxBuffer: 100 * 1024 * 1024, encoding: 'buffer' });
|
||||
return es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } })]);
|
||||
}
|
||||
|
||||
if (arch === 'armhf') {
|
||||
} else if (arch === 'armhf') {
|
||||
arch = 'armv7l';
|
||||
} else if (arch === 'alpine') {
|
||||
platform = 'alpine';
|
||||
arch = 'x64';
|
||||
}
|
||||
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from ${product.nodejs.repository}...`);
|
||||
|
||||
const checksumSha256 = getNodeChecksum(nodeVersion, platform, arch);
|
||||
|
||||
if (checksumSha256) {
|
||||
log(`Using SHA256 checksum for checking integrity: ${checksumSha256}`);
|
||||
} else {
|
||||
log.warn(`Unable to verify integrity of downloaded node.js binary because no SHA256 checksum was found!`);
|
||||
}
|
||||
|
||||
switch (platform) {
|
||||
case 'win32':
|
||||
return (product.nodejs.repository !== 'https://nodejs.org' ?
|
||||
fetchGithub(product.nodejs.repository, { version: product.nodejs.version, name: `win-${arch}-node.exe`, checksumSha256 }) :
|
||||
fetchUrls(`/dist/v${nodeVersion}/win-${arch}/node.exe`, { base: 'https://nodejs.org', checksumSha256 }))
|
||||
.pipe(rename('node.exe'));
|
||||
case 'darwin':
|
||||
case 'linux':
|
||||
return (product.nodejs.repository !== 'https://nodejs.org' ?
|
||||
fetchGithub(product.nodejs.repository, { version: product.nodejs.version, name: `node-v${nodeVersion}-${platform}-${arch}.tar.gz`, checksumSha256 }) :
|
||||
fetchUrls(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', checksumSha256 })
|
||||
).pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))
|
||||
.pipe(filter('**/node'))
|
||||
.pipe(util.setExecutableBit('**'))
|
||||
.pipe(rename('node'));
|
||||
case 'alpine': {
|
||||
const imageName = arch === 'arm64' ? 'arm64v8/node' : 'node';
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from docker image ${imageName}`);
|
||||
const contents = cp.execSync(`docker run --rm ${imageName}:${nodeVersion}-alpine /bin/sh -c 'cat \`which node\`'`, { maxBuffer: 100 * 1024 * 1024, encoding: 'buffer' });
|
||||
if (checksumSha256) {
|
||||
const actualSHA256Checksum = crypto.createHash('sha256').update(contents).digest('hex');
|
||||
if (actualSHA256Checksum !== checksumSha256) {
|
||||
throw new Error(`Checksum mismatch for node.js from docker image (expected ${options.checksumSha256}, actual ${actualSHA256Checksum}))`);
|
||||
}
|
||||
}
|
||||
return es.readArray([new File({ path: 'node', contents, stat: { mode: parseInt('755', 8) } })]);
|
||||
}
|
||||
}
|
||||
log(`Downloading node.js ${nodeVersion} ${platform} ${arch} from https://nodejs.org`);
|
||||
return remote(`/dist/v${nodeVersion}/node-v${nodeVersion}-${platform}-${arch}.tar.gz`, { base: 'https://nodejs.org', verbose: true })
|
||||
.pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar())))
|
||||
.pipe(filter('**/node'))
|
||||
.pipe(util.setExecutableBit('**'))
|
||||
.pipe(rename('node'));
|
||||
}
|
||||
|
||||
function packageTask(type, platform, arch, sourceFolderName, destinationFolderName) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -20,6 +20,7 @@ const mkdirp = require('mkdirp');
|
||||
export interface IExtensionDefinition {
|
||||
name: string;
|
||||
version: string;
|
||||
sha256: string;
|
||||
repo: string;
|
||||
platforms?: string[];
|
||||
metadata: {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -17,7 +17,7 @@ import * as os from 'os';
|
||||
import ts = require('typescript');
|
||||
import * as File from 'vinyl';
|
||||
import * as task from './task';
|
||||
import { Mangler } from './mangleTypeScript';
|
||||
import { Mangler } from './mangle/index';
|
||||
import { RawSourceMap } from 'source-map';
|
||||
const watch = require('./watch');
|
||||
|
||||
@@ -124,21 +124,22 @@ export function compileTask(src: string, out: string, build: boolean, options: {
|
||||
// mangle: TypeScript to TypeScript
|
||||
let mangleStream = es.through();
|
||||
if (build && !options.disableMangle) {
|
||||
let ts2tsMangler = new Mangler(compile.projectPath, (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data));
|
||||
let ts2tsMangler = new Mangler(compile.projectPath, (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data), { mangleExports: true, manglePrivateFields: true });
|
||||
const newContentsByFileName = ts2tsMangler.computeNewFileContents(new Set(['saveState']));
|
||||
mangleStream = es.through(function write(data: File & { sourceMap?: RawSourceMap }) {
|
||||
mangleStream = es.through(async function write(data: File & { sourceMap?: RawSourceMap }) {
|
||||
type TypeScriptExt = typeof ts & { normalizePath(path: string): string };
|
||||
const tsNormalPath = (<TypeScriptExt>ts).normalizePath(data.path);
|
||||
const newContents = newContentsByFileName.get(tsNormalPath);
|
||||
const newContents = (await newContentsByFileName).get(tsNormalPath);
|
||||
if (newContents !== undefined) {
|
||||
data.contents = Buffer.from(newContents.out);
|
||||
data.sourceMap = newContents.sourceMap && JSON.parse(newContents.sourceMap);
|
||||
}
|
||||
this.push(data);
|
||||
}, function end() {
|
||||
this.push(null);
|
||||
}, async function end() {
|
||||
// free resources
|
||||
newContentsByFileName.clear();
|
||||
(await newContentsByFileName).clear();
|
||||
|
||||
this.push(null);
|
||||
(<any>ts2tsMangler) = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ function darwinBundleDocumentTypes(types, icon) {
|
||||
});
|
||||
}
|
||||
exports.config = {
|
||||
version: product.electronRepository ? '22.5.5' : util.getElectronVersion(),
|
||||
version: product.electronRepository ? '22.5.7' : util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2023 Microsoft. All rights reserved',
|
||||
@@ -193,7 +193,7 @@ function getElectron(arch) {
|
||||
};
|
||||
}
|
||||
async function main(arch = process.arch) {
|
||||
const version = product.electronRepository ? '22.5.5' : util.getElectronVersion();
|
||||
const version = product.electronRepository ? '22.5.7' : 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.5.5' : util.getElectronVersion(),
|
||||
version: product.electronRepository ? '22.5.7' : util.getElectronVersion(),
|
||||
productAppName: product.nameLong,
|
||||
companyName: 'Microsoft Corporation',
|
||||
copyright: 'Copyright (C) 2023 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.5.5' : util.getElectronVersion();
|
||||
const version = product.electronRepository ? '22.5.7' : 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}`;
|
||||
|
||||
+16
-13
File diff suppressed because one or more lines are too long
+18
-23
@@ -22,10 +22,9 @@ const buffer = require('gulp-buffer');
|
||||
import * as jsoncParser from 'jsonc-parser';
|
||||
import webpack = require('webpack');
|
||||
import { getProductionDependencies } from './dependencies';
|
||||
import { getExtensionStream } from './builtInExtensions';
|
||||
import { IExtensionDefinition, getExtensionStream } from './builtInExtensions';
|
||||
import { getVersion } from './getVersion';
|
||||
import { remote, IOptions as IRemoteSrcOptions } from './gulpRemoteSource';
|
||||
import { assetFromGithub } from './github';
|
||||
import { fetchUrls, fetchGithub } from './fetch';
|
||||
|
||||
const root = path.dirname(path.dirname(__dirname));
|
||||
const commit = getVersion(root);
|
||||
@@ -222,7 +221,7 @@ const baseHeaders = {
|
||||
'X-Market-User-Id': '291C1CD0-051A-4123-9B4B-30D60EF52EE2',
|
||||
};
|
||||
|
||||
export function fromMarketplace(serviceUrl: string, { name: extensionName, version, metadata }: IBuiltInExtension): Stream {
|
||||
export function fromMarketplace(serviceUrl: string, { name: extensionName, version, sha256, metadata }: IExtensionDefinition): Stream {
|
||||
const json = require('gulp-json-editor') as typeof import('gulp-json-editor');
|
||||
|
||||
const [publisher, name] = extensionName.split('.');
|
||||
@@ -230,16 +229,15 @@ export function fromMarketplace(serviceUrl: string, { name: extensionName, versi
|
||||
|
||||
fancyLog('Downloading extension:', ansiColors.yellow(`${extensionName}@${version}`), '...');
|
||||
|
||||
const options: IRemoteSrcOptions = {
|
||||
base: url,
|
||||
fetchOptions: {
|
||||
headers: baseHeaders
|
||||
}
|
||||
};
|
||||
|
||||
const packageJsonFilter = filter('package.json', { restore: true });
|
||||
|
||||
return remote('', options)
|
||||
return fetchUrls('', {
|
||||
base: url,
|
||||
nodeFetchOptions: {
|
||||
headers: baseHeaders
|
||||
},
|
||||
checksumSha256: sha256
|
||||
})
|
||||
.pipe(vzip.src())
|
||||
.pipe(filter('extension/**'))
|
||||
.pipe(rename(p => p.dirname = p.dirname!.replace(/^extension\/?/, '')))
|
||||
@@ -250,14 +248,18 @@ export function fromMarketplace(serviceUrl: string, { name: extensionName, versi
|
||||
}
|
||||
|
||||
|
||||
export function fromGithub({ name, version, repo, metadata }: IBuiltInExtension): Stream {
|
||||
export function fromGithub({ name, version, repo, sha256, metadata }: IExtensionDefinition): Stream {
|
||||
const json = require('gulp-json-editor') as typeof import('gulp-json-editor');
|
||||
|
||||
fancyLog('Downloading extension from GH:', ansiColors.yellow(`${name}@${version}`), '...');
|
||||
|
||||
const packageJsonFilter = filter('package.json', { restore: true });
|
||||
|
||||
return assetFromGithub(new URL(repo).pathname, version, name => name.endsWith('.vsix'))
|
||||
return fetchGithub(new URL(repo).pathname, {
|
||||
version,
|
||||
name: name => name.endsWith('.vsix'),
|
||||
checksumSha256: sha256
|
||||
})
|
||||
.pipe(buffer())
|
||||
.pipe(vzip.src())
|
||||
.pipe(filter('extension/**'))
|
||||
@@ -284,16 +286,9 @@ const marketplaceWebExtensionsExclude = new Set([
|
||||
'ms-vscode.vscode-js-profile-table'
|
||||
]);
|
||||
|
||||
interface IBuiltInExtension {
|
||||
name: string;
|
||||
version: string;
|
||||
repo: string;
|
||||
metadata: any;
|
||||
}
|
||||
|
||||
const productJson = JSON.parse(fs.readFileSync(path.join(__dirname, '../../product.json'), 'utf8'));
|
||||
const builtInExtensions: IBuiltInExtension[] = productJson.builtInExtensions || [];
|
||||
const webBuiltInExtensions: IBuiltInExtension[] = productJson.webBuiltInExtensions || [];
|
||||
const builtInExtensions: IExtensionDefinition[] = productJson.builtInExtensions || [];
|
||||
const webBuiltInExtensions: IExtensionDefinition[] = productJson.webBuiltInExtensions || [];
|
||||
|
||||
type ExtensionKind = 'ui' | 'workspace' | 'web';
|
||||
interface IExtensionManifest {
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,147 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as es from 'event-stream';
|
||||
import fetch, { RequestInit } from 'node-fetch';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import * as log from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
import * as crypto from 'crypto';
|
||||
import * as through2 from 'through2';
|
||||
import { Stream } from 'stream';
|
||||
|
||||
export interface IFetchOptions {
|
||||
base?: string;
|
||||
nodeFetchOptions?: RequestInit;
|
||||
verbose?: boolean;
|
||||
checksumSha256?: string;
|
||||
}
|
||||
|
||||
export function fetchUrls(urls: string[] | string, options: IFetchOptions): es.ThroughStream {
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (typeof options.base !== 'string' && options.base !== null) {
|
||||
options.base = '/';
|
||||
}
|
||||
|
||||
if (!Array.isArray(urls)) {
|
||||
urls = [urls];
|
||||
}
|
||||
|
||||
return es.readArray(urls).pipe(es.map<string, VinylFile | void>((data: string, cb) => {
|
||||
const url = [options.base, data].join('');
|
||||
fetchUrl(url, options).then(file => {
|
||||
cb(undefined, file);
|
||||
}, error => {
|
||||
cb(error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
export async function fetchUrl(url: string, options: IFetchOptions, retries = 10, retryDelay = 1000): Promise<VinylFile> {
|
||||
const verbose = !!options.verbose ?? (!!process.env['CI'] || !!process.env['BUILD_ARTIFACTSTAGINGDIRECTORY']);
|
||||
try {
|
||||
let startTime = 0;
|
||||
if (verbose) {
|
||||
log(`Start fetching ${ansiColors.magenta(url)}${retries !== 10 ? `(${10 - retries} retry}` : ''}`);
|
||||
startTime = new Date().getTime();
|
||||
}
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options.nodeFetchOptions,
|
||||
signal: controller.signal as any /* Typings issue with lib.dom.d.ts */
|
||||
});
|
||||
if (verbose) {
|
||||
log(`Fetch completed: Status ${response.status}. Took ${ansiColors.magenta(`${new Date().getTime() - startTime} ms`)}`);
|
||||
}
|
||||
if (response.ok && (response.status >= 200 && response.status < 300)) {
|
||||
const contents = await response.buffer();
|
||||
if (options.checksumSha256) {
|
||||
const actualSHA256Checksum = crypto.createHash('sha256').update(contents).digest('hex');
|
||||
if (actualSHA256Checksum !== options.checksumSha256) {
|
||||
throw new Error(`Checksum mismatch for ${ansiColors.cyan(url)} (expected ${options.checksumSha256}, actual ${actualSHA256Checksum}))`);
|
||||
} else if (verbose) {
|
||||
log(`Verified SHA256 checksums match for ${ansiColors.cyan(url)}`);
|
||||
}
|
||||
} else if (verbose) {
|
||||
log(`Skipping checksum verification for ${ansiColors.cyan(url)} because no expected checksum was provided`);
|
||||
}
|
||||
if (verbose) {
|
||||
log(`Fetched response body buffer: ${ansiColors.magenta(`${(contents as Buffer).byteLength} bytes`)}`);
|
||||
}
|
||||
return new VinylFile({
|
||||
cwd: '/',
|
||||
base: options.base,
|
||||
path: url,
|
||||
contents
|
||||
});
|
||||
}
|
||||
throw new Error(`Request ${ansiColors.magenta(url)} failed with status code: ${response.status}`);
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
} catch (e) {
|
||||
if (verbose) {
|
||||
log(`Fetching ${ansiColors.cyan(url)} failed: ${e}`);
|
||||
}
|
||||
if (retries > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
return fetchUrl(url, options, retries - 1, retryDelay);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
const ghApiHeaders: Record<string, string> = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'VSCode Build',
|
||||
};
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
|
||||
}
|
||||
const ghDownloadHeaders = {
|
||||
...ghApiHeaders,
|
||||
Accept: 'application/octet-stream',
|
||||
};
|
||||
|
||||
export interface IGitHubAssetOptions {
|
||||
version: string;
|
||||
name: string | ((name: string) => boolean);
|
||||
checksumSha256?: string;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param repo for example `Microsoft/vscode`
|
||||
* @param version for example `16.17.1` - must be a valid releases tag
|
||||
* @param assetName for example (name) => name === `win-x64-node.exe` - must be an asset that exists
|
||||
* @returns a stream with the asset as file
|
||||
*/
|
||||
export function fetchGithub(repo: string, options: IGitHubAssetOptions): Stream {
|
||||
return fetchUrls(`/repos/${repo.replace(/^\/|\/$/g, '')}/releases/tags/v${options.version}`, {
|
||||
base: 'https://api.github.com',
|
||||
verbose: options.verbose,
|
||||
nodeFetchOptions: { headers: ghApiHeaders }
|
||||
}).pipe(through2.obj(async function (file, _enc, callback) {
|
||||
const assetFilter = typeof options.name === 'string' ? (name: string) => name === options.name : options.name;
|
||||
const asset = JSON.parse(file.contents.toString()).assets.find((a: { name: string }) => assetFilter(a.name));
|
||||
if (!asset) {
|
||||
return callback(new Error(`Could not find asset in release of ${repo} @ ${options.version}`));
|
||||
}
|
||||
try {
|
||||
callback(null, await fetchUrl(asset.url, {
|
||||
nodeFetchOptions: { headers: ghDownloadHeaders },
|
||||
verbose: options.verbose,
|
||||
checksumSha256: options.checksumSha256
|
||||
}));
|
||||
} catch (error) {
|
||||
callback(error);
|
||||
}
|
||||
}));
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.assetFromGithub = void 0;
|
||||
const node_fetch_1 = require("node-fetch");
|
||||
const gulpRemoteSource_1 = require("./gulpRemoteSource");
|
||||
const through2 = require("through2");
|
||||
const ghApiHeaders = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'VSCode Build',
|
||||
};
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
|
||||
}
|
||||
const ghDownloadHeaders = {
|
||||
...ghApiHeaders,
|
||||
Accept: 'application/octet-stream',
|
||||
};
|
||||
/**
|
||||
* @param repo for example `Microsoft/vscode`
|
||||
* @param version for example `16.17.1` - must be a valid releases tag
|
||||
* @param assetName for example (name) => name === `win-x64-node.exe` - must be an asset that exists
|
||||
* @returns a stream with the asset as file
|
||||
*/
|
||||
function assetFromGithub(repo, version, assetFilter) {
|
||||
return (0, gulpRemoteSource_1.remote)(`/repos/${repo.replace(/^\/|\/$/g, '')}/releases/tags/v${version}`, {
|
||||
base: 'https://api.github.com',
|
||||
fetchOptions: { headers: ghApiHeaders }
|
||||
}).pipe(through2.obj(async function (file, _enc, callback) {
|
||||
const asset = JSON.parse(file.contents.toString()).assets.find((a) => assetFilter(a.name));
|
||||
if (!asset) {
|
||||
return callback(new Error(`Could not find asset in release of ${repo} @ ${version}`));
|
||||
}
|
||||
const response = await (0, node_fetch_1.default)(asset.url, { headers: ghDownloadHeaders });
|
||||
if (response.ok) {
|
||||
file.contents = response.body.pipe(through2());
|
||||
callback(null, file);
|
||||
}
|
||||
else {
|
||||
return callback(new Error(`Request ${response.url} failed with status code: ${response.status}`));
|
||||
}
|
||||
}));
|
||||
}
|
||||
exports.assetFromGithub = assetFromGithub;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2l0aHViLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZ2l0aHViLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBR2hHLDJDQUErQjtBQUMvQix5REFBNEM7QUFDNUMscUNBQXFDO0FBRXJDLE1BQU0sWUFBWSxHQUEyQjtJQUM1QyxNQUFNLEVBQUUsZ0NBQWdDO0lBQ3hDLFlBQVksRUFBRSxjQUFjO0NBQzVCLENBQUM7QUFDRixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFO0lBQzdCLFlBQVksQ0FBQyxhQUFhLEdBQUcsUUFBUSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLENBQUM7Q0FDakc7QUFDRCxNQUFNLGlCQUFpQixHQUFHO0lBQ3pCLEdBQUcsWUFBWTtJQUNmLE1BQU0sRUFBRSwwQkFBMEI7Q0FDbEMsQ0FBQztBQUVGOzs7OztHQUtHO0FBQ0gsU0FBZ0IsZUFBZSxDQUFDLElBQVksRUFBRSxPQUFlLEVBQUUsV0FBc0M7SUFDcEcsT0FBTyxJQUFBLHlCQUFNLEVBQUMsVUFBVSxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxFQUFFLENBQUMsbUJBQW1CLE9BQU8sRUFBRSxFQUFFO1FBQ2pGLElBQUksRUFBRSx3QkFBd0I7UUFDOUIsWUFBWSxFQUFFLEVBQUUsT0FBTyxFQUFFLFlBQVksRUFBRTtLQUN2QyxDQUFDLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsS0FBSyxXQUFXLElBQUksRUFBRSxJQUFJLEVBQUUsUUFBUTtRQUN4RCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBbUIsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQzdHLElBQUksQ0FBQyxLQUFLLEVBQUU7WUFDWCxPQUFPLFFBQVEsQ0FBQyxJQUFJLEtBQUssQ0FBQyxzQ0FBc0MsSUFBSSxNQUFNLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQztTQUN0RjtRQUNELE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBQSxvQkFBSyxFQUFDLEtBQUssQ0FBQyxHQUFHLEVBQUUsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDO1FBQ3hFLElBQUksUUFBUSxDQUFDLEVBQUUsRUFBRTtZQUNoQixJQUFJLENBQUMsUUFBUSxHQUFHLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDL0MsUUFBUSxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQztTQUNyQjthQUFNO1lBQ04sT0FBTyxRQUFRLENBQUMsSUFBSSxLQUFLLENBQUMsV0FBVyxRQUFRLENBQUMsR0FBRyw2QkFBNkIsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztTQUNsRztJQUVGLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBbEJELDBDQWtCQyJ9
|
||||
@@ -1,47 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Stream } from 'stream';
|
||||
import fetch from 'node-fetch';
|
||||
import { remote } from './gulpRemoteSource';
|
||||
import * as through2 from 'through2';
|
||||
|
||||
const ghApiHeaders: Record<string, string> = {
|
||||
Accept: 'application/vnd.github.v3+json',
|
||||
'User-Agent': 'VSCode Build',
|
||||
};
|
||||
if (process.env.GITHUB_TOKEN) {
|
||||
ghApiHeaders.Authorization = 'Basic ' + Buffer.from(process.env.GITHUB_TOKEN).toString('base64');
|
||||
}
|
||||
const ghDownloadHeaders = {
|
||||
...ghApiHeaders,
|
||||
Accept: 'application/octet-stream',
|
||||
};
|
||||
|
||||
/**
|
||||
* @param repo for example `Microsoft/vscode`
|
||||
* @param version for example `16.17.1` - must be a valid releases tag
|
||||
* @param assetName for example (name) => name === `win-x64-node.exe` - must be an asset that exists
|
||||
* @returns a stream with the asset as file
|
||||
*/
|
||||
export function assetFromGithub(repo: string, version: string, assetFilter: (name: string) => boolean): Stream {
|
||||
return remote(`/repos/${repo.replace(/^\/|\/$/g, '')}/releases/tags/v${version}`, {
|
||||
base: 'https://api.github.com',
|
||||
fetchOptions: { headers: ghApiHeaders }
|
||||
}).pipe(through2.obj(async function (file, _enc, callback) {
|
||||
const asset = JSON.parse(file.contents.toString()).assets.find((a: { name: string }) => assetFilter(a.name));
|
||||
if (!asset) {
|
||||
return callback(new Error(`Could not find asset in release of ${repo} @ ${version}`));
|
||||
}
|
||||
const response = await fetch(asset.url, { headers: ghDownloadHeaders });
|
||||
if (response.ok) {
|
||||
file.contents = response.body.pipe(through2());
|
||||
callback(null, file);
|
||||
} else {
|
||||
return callback(new Error(`Request ${response.url} failed with status code: ${response.status}`));
|
||||
}
|
||||
|
||||
}));
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.remote = void 0;
|
||||
const es = require("event-stream");
|
||||
const node_fetch_1 = require("node-fetch");
|
||||
const VinylFile = require("vinyl");
|
||||
const through2 = require("through2");
|
||||
const log = require("fancy-log");
|
||||
const ansiColors = require("ansi-colors");
|
||||
function remote(urls, options) {
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
if (typeof options.base !== 'string' && options.base !== null) {
|
||||
options.base = '/';
|
||||
}
|
||||
if (typeof options.buffer !== 'boolean') {
|
||||
options.buffer = true;
|
||||
}
|
||||
if (!Array.isArray(urls)) {
|
||||
urls = [urls];
|
||||
}
|
||||
return es.readArray(urls).pipe(es.map((data, cb) => {
|
||||
const url = [options.base, data].join('');
|
||||
fetchWithRetry(url, options).then(file => {
|
||||
cb(undefined, file);
|
||||
}, error => {
|
||||
cb(error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
exports.remote = remote;
|
||||
async function fetchWithRetry(url, options, retries = 10, retryDelay = 1000) {
|
||||
try {
|
||||
let startTime = 0;
|
||||
if (options.verbose) {
|
||||
log(`Start fetching ${ansiColors.magenta(url)}${retries !== 10 ? `(${10 - retries} retry}` : ''}`);
|
||||
startTime = new Date().getTime();
|
||||
}
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
|
||||
try {
|
||||
const response = await (0, node_fetch_1.default)(url, {
|
||||
...options.fetchOptions,
|
||||
signal: controller.signal /* Typings issue with lib.dom.d.ts */
|
||||
});
|
||||
if (options.verbose) {
|
||||
log(`Fetch completed: Status ${response.status}. Took ${ansiColors.magenta(`${new Date().getTime() - startTime} ms`)}`);
|
||||
}
|
||||
if (response.ok && (response.status >= 200 && response.status < 300)) {
|
||||
// request must be piped out once created, or we'll get this error: "You cannot pipe after data has been emitted from the response."
|
||||
const contents = options.buffer ? await response.buffer() : response.body.pipe(through2());
|
||||
if (options.buffer && options.verbose) {
|
||||
log(`Fetched response body buffer: ${ansiColors.magenta(`${contents.byteLength} bytes`)}`);
|
||||
}
|
||||
return new VinylFile({
|
||||
cwd: '/',
|
||||
base: options.base,
|
||||
path: url,
|
||||
contents
|
||||
});
|
||||
}
|
||||
throw new Error(`Request ${ansiColors.magenta(url)} failed with status code: ${response.status}`);
|
||||
}
|
||||
finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
if (options.verbose) {
|
||||
log(`Fetching ${ansiColors.cyan(url)} failed: ${e}`);
|
||||
}
|
||||
if (retries > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
return fetchWithRetry(url, options, retries - 1, retryDelay);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3VscFJlbW90ZVNvdXJjZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImd1bHBSZW1vdGVTb3VyY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOzs7QUFFaEcsbUNBQW1DO0FBQ25DLDJDQUFnRDtBQUNoRCxtQ0FBbUM7QUFDbkMscUNBQXFDO0FBQ3JDLGlDQUFpQztBQUNqQywwQ0FBMEM7QUFTMUMsU0FBZ0IsTUFBTSxDQUFDLElBQXVCLEVBQUUsT0FBaUI7SUFDaEUsSUFBSSxPQUFPLEtBQUssU0FBUyxFQUFFO1FBQzFCLE9BQU8sR0FBRyxFQUFFLENBQUM7S0FDYjtJQUVELElBQUksT0FBTyxPQUFPLENBQUMsSUFBSSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLElBQUksRUFBRTtRQUM5RCxPQUFPLENBQUMsSUFBSSxHQUFHLEdBQUcsQ0FBQztLQUNuQjtJQUVELElBQUksT0FBTyxPQUFPLENBQUMsTUFBTSxLQUFLLFNBQVMsRUFBRTtRQUN4QyxPQUFPLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztLQUN0QjtJQUVELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFO1FBQ3pCLElBQUksR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO0tBQ2Q7SUFFRCxPQUFPLEVBQUUsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQTJCLENBQUMsSUFBWSxFQUFFLEVBQUUsRUFBRSxFQUFFO1FBQ3BGLE1BQU0sR0FBRyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7UUFDMUMsY0FBYyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDeEMsRUFBRSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUNyQixDQUFDLEVBQUUsS0FBSyxDQUFDLEVBQUU7WUFDVixFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDWCxDQUFDLENBQUMsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDO0FBekJELHdCQXlCQztBQUVELEtBQUssVUFBVSxjQUFjLENBQUMsR0FBVyxFQUFFLE9BQWlCLEVBQUUsT0FBTyxHQUFHLEVBQUUsRUFBRSxVQUFVLEdBQUcsSUFBSTtJQUM1RixJQUFJO1FBQ0gsSUFBSSxTQUFTLEdBQUcsQ0FBQyxDQUFDO1FBQ2xCLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRTtZQUNwQixHQUFHLENBQUMsa0JBQWtCLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEdBQUcsT0FBTyxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLEdBQUcsT0FBTyxTQUFTLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUM7WUFDbkcsU0FBUyxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsT0FBTyxFQUFFLENBQUM7U0FDakM7UUFDRCxNQUFNLFVBQVUsR0FBRyxJQUFJLGVBQWUsRUFBRSxDQUFDO1FBQ3pDLE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxVQUFVLENBQUMsS0FBSyxFQUFFLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQ2hFLElBQUk7WUFDSCxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUEsb0JBQUssRUFBQyxHQUFHLEVBQUU7Z0JBQ2pDLEdBQUcsT0FBTyxDQUFDLFlBQVk7Z0JBQ3ZCLE1BQU0sRUFBRSxVQUFVLENBQUMsTUFBYSxDQUFDLHFDQUFxQzthQUN0RSxDQUFDLENBQUM7WUFDSCxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUU7Z0JBQ3BCLEdBQUcsQ0FBQywyQkFBMkIsUUFBUSxDQUFDLE1BQU0sVUFBVSxVQUFVLENBQUMsT0FBTyxDQUFDLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQyxPQUFPLEVBQUUsR0FBRyxTQUFTLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQzthQUN4SDtZQUNELElBQUksUUFBUSxDQUFDLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLElBQUksR0FBRyxJQUFJLFFBQVEsQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLEVBQUU7Z0JBQ3JFLG9JQUFvSTtnQkFDcEksTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsTUFBTSxRQUFRLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUM7Z0JBQzNGLElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFO29CQUN0QyxHQUFHLENBQUMsaUNBQWlDLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBSSxRQUFtQixDQUFDLFVBQVUsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO2lCQUN2RztnQkFDRCxPQUFPLElBQUksU0FBUyxDQUFDO29CQUNwQixHQUFHLEVBQUUsR0FBRztvQkFDUixJQUFJLEVBQUUsT0FBTyxDQUFDLElBQUk7b0JBQ2xCLElBQUksRUFBRSxHQUFHO29CQUNULFFBQVE7aUJBQ1IsQ0FBQyxDQUFDO2FBQ0g7WUFDRCxNQUFNLElBQUksS0FBSyxDQUFDLFdBQVcsVUFBVSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsNkJBQTZCLFFBQVEsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1NBQ2xHO2dCQUFTO1lBQ1QsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1NBQ3RCO0tBQ0Q7SUFBQyxPQUFPLENBQUMsRUFBRTtRQUNYLElBQUksT0FBTyxDQUFDLE9BQU8sRUFBRTtZQUNwQixHQUFHLENBQUMsWUFBWSxVQUFVLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDLENBQUM7U0FDckQ7UUFDRCxJQUFJLE9BQU8sR0FBRyxDQUFDLEVBQUU7WUFDaEIsTUFBTSxJQUFJLE9BQU8sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUMsQ0FBQztZQUM5RCxPQUFPLGNBQWMsQ0FBQyxHQUFHLEVBQUUsT0FBTyxFQUFFLE9BQU8sR0FBRyxDQUFDLEVBQUUsVUFBVSxDQUFDLENBQUM7U0FDN0Q7UUFDRCxNQUFNLENBQUMsQ0FBQztLQUNSO0FBQ0YsQ0FBQyJ9
|
||||
@@ -1,95 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as es from 'event-stream';
|
||||
import fetch, { RequestInit } from 'node-fetch';
|
||||
import * as VinylFile from 'vinyl';
|
||||
import * as through2 from 'through2';
|
||||
import * as log from 'fancy-log';
|
||||
import * as ansiColors from 'ansi-colors';
|
||||
|
||||
export interface IOptions {
|
||||
base?: string;
|
||||
buffer?: boolean;
|
||||
fetchOptions?: RequestInit;
|
||||
verbose?: boolean;
|
||||
}
|
||||
|
||||
export function remote(urls: string[] | string, options: IOptions): es.ThroughStream {
|
||||
if (options === undefined) {
|
||||
options = {};
|
||||
}
|
||||
|
||||
if (typeof options.base !== 'string' && options.base !== null) {
|
||||
options.base = '/';
|
||||
}
|
||||
|
||||
if (typeof options.buffer !== 'boolean') {
|
||||
options.buffer = true;
|
||||
}
|
||||
|
||||
if (!Array.isArray(urls)) {
|
||||
urls = [urls];
|
||||
}
|
||||
|
||||
return es.readArray(urls).pipe(es.map<string, VinylFile | void>((data: string, cb) => {
|
||||
const url = [options.base, data].join('');
|
||||
fetchWithRetry(url, options).then(file => {
|
||||
cb(undefined, file);
|
||||
}, error => {
|
||||
cb(error);
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
async function fetchWithRetry(url: string, options: IOptions, retries = 10, retryDelay = 1000): Promise<VinylFile> {
|
||||
try {
|
||||
let startTime = 0;
|
||||
if (options.verbose) {
|
||||
log(`Start fetching ${ansiColors.magenta(url)}${retries !== 10 ? `(${10 - retries} retry}` : ''}`);
|
||||
startTime = new Date().getTime();
|
||||
}
|
||||
const controller = new AbortController();
|
||||
const timeout = setTimeout(() => controller.abort(), 30 * 1000);
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
...options.fetchOptions,
|
||||
signal: controller.signal as any /* Typings issue with lib.dom.d.ts */
|
||||
});
|
||||
if (options.verbose) {
|
||||
log(`Fetch completed: Status ${response.status}. Took ${ansiColors.magenta(`${new Date().getTime() - startTime} ms`)}`);
|
||||
}
|
||||
if (response.ok && (response.status >= 200 && response.status < 300)) {
|
||||
// request must be piped out once created, or we'll get this error: "You cannot pipe after data has been emitted from the response."
|
||||
const contents = options.buffer ? await response.buffer() : response.body.pipe(through2());
|
||||
if (options.buffer && options.verbose) {
|
||||
log(`Fetched response body buffer: ${ansiColors.magenta(`${(contents as Buffer).byteLength} bytes`)}`);
|
||||
}
|
||||
return new VinylFile({
|
||||
cwd: '/',
|
||||
base: options.base,
|
||||
path: url,
|
||||
contents
|
||||
});
|
||||
}
|
||||
throw new Error(`Request ${ansiColors.magenta(url)} failed with status code: ${response.status}`);
|
||||
} finally {
|
||||
clearTimeout(timeout);
|
||||
}
|
||||
} catch (e) {
|
||||
if (options.verbose) {
|
||||
log(`Fetching ${ansiColors.cyan(url)} failed: ${e}`);
|
||||
}
|
||||
if (retries > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, retryDelay));
|
||||
return fetchWithRetry(url, options, retries - 1, retryDelay);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -521,6 +521,10 @@
|
||||
{
|
||||
"name": "vs/workbench/contrib/accessibility",
|
||||
"project": "vscode-workbench"
|
||||
},
|
||||
{
|
||||
"name": "vs/workbench/services/issue",
|
||||
"project": "vscode-workbench"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -3,12 +3,15 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { argv } from 'process';
|
||||
import { Mapping, SourceMapGenerator } from 'source-map';
|
||||
import * as ts from 'typescript';
|
||||
import { pathToFileURL } from 'url';
|
||||
import * as workerpool from 'workerpool';
|
||||
import { StaticLanguageServiceHost } from './staticLanguageServiceHost';
|
||||
const buildfile = require('../../../src/buildfile');
|
||||
|
||||
class ShortIdent {
|
||||
|
||||
@@ -17,21 +20,20 @@ class ShortIdent {
|
||||
'import', 'in', 'instanceof', 'let', 'new', 'null', 'return', 'static', 'super', 'switch', 'this', 'throw',
|
||||
'true', 'try', 'typeof', 'var', 'void', 'while', 'with', 'yield']);
|
||||
|
||||
private static _alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
|
||||
private static _alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890$_'.split('');
|
||||
|
||||
private _value = 0;
|
||||
private readonly _isNameTaken: (name: string) => boolean;
|
||||
|
||||
constructor(isNameTaken: (name: string) => boolean) {
|
||||
this._isNameTaken = name => ShortIdent._keywords.has(name) || isNameTaken(name);
|
||||
}
|
||||
constructor(
|
||||
private readonly prefix: string
|
||||
) { }
|
||||
|
||||
next(): string {
|
||||
const candidate = ShortIdent.convert(this._value);
|
||||
next(isNameTaken?: (name: string) => boolean): string {
|
||||
const candidate = this.prefix + ShortIdent.convert(this._value);
|
||||
this._value++;
|
||||
if (this._isNameTaken(candidate)) {
|
||||
if (ShortIdent._keywords.has(candidate) || /^[_0-9]/.test(candidate) || isNameTaken?.(candidate)) {
|
||||
// try again
|
||||
return this.next();
|
||||
return this.next(isNameTaken);
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
@@ -181,8 +183,7 @@ class ClassData {
|
||||
|
||||
data.replacements = new Map();
|
||||
|
||||
const identPool = new ShortIdent(name => {
|
||||
|
||||
const isNameTaken = (name: string) => {
|
||||
// locally taken
|
||||
if (data._isNameTaken(name)) {
|
||||
return true;
|
||||
@@ -212,11 +213,12 @@ class ClassData {
|
||||
}
|
||||
|
||||
return false;
|
||||
});
|
||||
};
|
||||
const identPool = new ShortIdent('');
|
||||
|
||||
for (const [name, info] of data.fields) {
|
||||
if (ClassData._shouldMangle(info.type)) {
|
||||
const shortName = identPool.next();
|
||||
const shortName = identPool.next(isNameTaken);
|
||||
data.replacements.set(name, shortName);
|
||||
}
|
||||
}
|
||||
@@ -237,12 +239,11 @@ class ClassData {
|
||||
}
|
||||
}
|
||||
}
|
||||
if ((<any>this.node.getSourceFile()).identifiers instanceof Map) {
|
||||
// taken by any other usage
|
||||
if ((<any>this.node.getSourceFile()).identifiers.has(name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (isNameTakenInFile(this.node, name)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -267,59 +268,122 @@ class ClassData {
|
||||
}
|
||||
}
|
||||
|
||||
class StaticLanguageServiceHost implements ts.LanguageServiceHost {
|
||||
|
||||
private readonly _cmdLine: ts.ParsedCommandLine;
|
||||
private readonly _scriptSnapshots: Map<string, ts.IScriptSnapshot> = new Map();
|
||||
|
||||
constructor(readonly projectPath: string) {
|
||||
const existingOptions: Partial<ts.CompilerOptions> = {};
|
||||
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
|
||||
if (parsed.error) {
|
||||
throw parsed.error;
|
||||
}
|
||||
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
|
||||
if (this._cmdLine.errors.length > 0) {
|
||||
throw parsed.error;
|
||||
function isNameTakenInFile(node: ts.Node, name: string): boolean {
|
||||
const identifiers = (<any>node.getSourceFile()).identifiers;
|
||||
if (identifiers instanceof Map) {
|
||||
if (identifiers.has(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
getCompilationSettings(): ts.CompilerOptions {
|
||||
return this._cmdLine.options;
|
||||
return false;
|
||||
}
|
||||
|
||||
const fileIdents = new class {
|
||||
private readonly idents = new ShortIdent('$');
|
||||
|
||||
next() {
|
||||
return this.idents.next();
|
||||
}
|
||||
getScriptFileNames(): string[] {
|
||||
return this._cmdLine.fileNames;
|
||||
};
|
||||
|
||||
const skippedExportMangledFiles = [
|
||||
// Build
|
||||
'css.build',
|
||||
'nls.build',
|
||||
|
||||
// Monaco
|
||||
'editorCommon',
|
||||
'editorOptions',
|
||||
'editorZoom',
|
||||
'standaloneEditor',
|
||||
'standaloneEnums',
|
||||
'standaloneLanguages',
|
||||
|
||||
// Generated
|
||||
'extensionsApiProposals',
|
||||
|
||||
// Module passed around as type
|
||||
'pfs',
|
||||
|
||||
// entry points
|
||||
...[
|
||||
buildfile.entrypoint('vs/server/node/server.main', []),
|
||||
buildfile.entrypoint('vs/workbench/workbench.desktop.main', []),
|
||||
buildfile.base,
|
||||
buildfile.workerExtensionHost,
|
||||
buildfile.workerNotebook,
|
||||
buildfile.workerLanguageDetection,
|
||||
buildfile.workerLocalFileSearch,
|
||||
buildfile.workerProfileAnalysis,
|
||||
buildfile.workbenchDesktop,
|
||||
buildfile.workbenchWeb,
|
||||
buildfile.code
|
||||
].flat().map(x => x.name),
|
||||
];
|
||||
|
||||
const skippedExportMangledProjects = [
|
||||
// Test projects
|
||||
'vscode-api-tests',
|
||||
|
||||
// These projects use webpack to dynamically rewrite imports, which messes up our mangling
|
||||
'configuration-editing',
|
||||
'microsoft-authentication',
|
||||
'github-authentication',
|
||||
'html-language-features/server',
|
||||
];
|
||||
|
||||
const skippedExportMangledSymbols = [
|
||||
// Don't mangle extension entry points
|
||||
'activate',
|
||||
'deactivate',
|
||||
];
|
||||
|
||||
class DeclarationData {
|
||||
|
||||
readonly replacementName: string;
|
||||
|
||||
constructor(
|
||||
readonly fileName: string,
|
||||
readonly node: ts.FunctionDeclaration | ts.ClassDeclaration | ts.EnumDeclaration | ts.VariableDeclaration,
|
||||
private readonly service: ts.LanguageService,
|
||||
) {
|
||||
// Todo: generate replacement names based on usage count, with more used names getting shorter identifiers
|
||||
this.replacementName = fileIdents.next();
|
||||
}
|
||||
getScriptVersion(_fileName: string): string {
|
||||
return '1';
|
||||
}
|
||||
getProjectVersion(): string {
|
||||
return '1';
|
||||
}
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
|
||||
let result: ts.IScriptSnapshot | undefined = this._scriptSnapshots.get(fileName);
|
||||
if (result === undefined) {
|
||||
const content = ts.sys.readFile(fileName);
|
||||
if (content === undefined) {
|
||||
return undefined;
|
||||
|
||||
get locations(): Iterable<{ fileName: string; offset: number }> {
|
||||
if (ts.isVariableDeclaration(this.node)) {
|
||||
// If the const aliases any types, we need to rename those too
|
||||
const definitionResult = this.service.getDefinitionAndBoundSpan(this.fileName, this.node.name.getStart());
|
||||
if (definitionResult?.definitions && definitionResult.definitions.length > 1) {
|
||||
return definitionResult.definitions.map(x => ({ fileName: x.fileName, offset: x.textSpan.start }));
|
||||
}
|
||||
result = ts.ScriptSnapshot.fromString(content);
|
||||
this._scriptSnapshots.set(fileName, result);
|
||||
}
|
||||
return result;
|
||||
|
||||
return [{
|
||||
fileName: this.fileName,
|
||||
offset: this.node.name!.getStart()
|
||||
}];
|
||||
}
|
||||
getCurrentDirectory(): string {
|
||||
return path.dirname(this.projectPath);
|
||||
|
||||
shouldMangle(newName: string): boolean {
|
||||
const currentName = this.node.name!.getText();
|
||||
if (currentName.startsWith('$') || skippedExportMangledSymbols.includes(currentName)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// New name is longer the existing one :'(
|
||||
if (newName.length >= currentName.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't mangle functions we've explicitly opted out
|
||||
if (this.node.getFullText().includes('@skipMangle')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
return ts.getDefaultLibFilePath(options);
|
||||
}
|
||||
directoryExists = ts.sys.directoryExists;
|
||||
getDirectories = ts.sys.getDirectories;
|
||||
fileExists = ts.sys.fileExists;
|
||||
readFile = ts.sys.readFile;
|
||||
readDirectory = ts.sys.readDirectory;
|
||||
// this is necessary to make source references work.
|
||||
realpath = ts.sys.realpath;
|
||||
}
|
||||
|
||||
export interface MangleOutput {
|
||||
@@ -339,26 +403,82 @@ export interface MangleOutput {
|
||||
export class Mangler {
|
||||
|
||||
private readonly allClassDataByKey = new Map<string, ClassData>();
|
||||
private readonly allExportedSymbols = new Set<DeclarationData>();
|
||||
|
||||
private readonly service: ts.LanguageService;
|
||||
private readonly renameWorkerPool: workerpool.WorkerPool;
|
||||
|
||||
constructor(readonly projectPath: string, readonly log: typeof console.log = () => { }) {
|
||||
constructor(
|
||||
private readonly projectPath: string,
|
||||
private readonly log: typeof console.log = () => { },
|
||||
private readonly config: { readonly manglePrivateFields: boolean; readonly mangleExports: boolean },
|
||||
) {
|
||||
this.service = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
|
||||
|
||||
this.renameWorkerPool = workerpool.pool(path.join(__dirname, 'renameWorker.js'), {
|
||||
maxWorkers: 2,
|
||||
minWorkers: 'max'
|
||||
});
|
||||
}
|
||||
|
||||
computeNewFileContents(strictImplicitPublicHandling?: Set<string>): Map<string, MangleOutput> {
|
||||
async computeNewFileContents(strictImplicitPublicHandling?: Set<string>): Promise<Map<string, MangleOutput>> {
|
||||
|
||||
// STEP: find all classes and their field info
|
||||
// STEP:
|
||||
// - Find all classes and their field info.
|
||||
// - Find exported symbols.
|
||||
|
||||
const visit = (node: ts.Node): void => {
|
||||
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
|
||||
const anchor = node.name ?? node;
|
||||
const key = `${node.getSourceFile().fileName}|${anchor.getStart()}`;
|
||||
if (this.allClassDataByKey.has(key)) {
|
||||
throw new Error('DUPE?');
|
||||
if (this.config.manglePrivateFields) {
|
||||
if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) {
|
||||
const anchor = node.name ?? node;
|
||||
const key = `${node.getSourceFile().fileName}|${anchor.getStart()}`;
|
||||
if (this.allClassDataByKey.has(key)) {
|
||||
throw new Error('DUPE?');
|
||||
}
|
||||
this.allClassDataByKey.set(key, new ClassData(node.getSourceFile().fileName, node));
|
||||
}
|
||||
this.allClassDataByKey.set(key, new ClassData(node.getSourceFile().fileName, node));
|
||||
}
|
||||
|
||||
if (this.config.mangleExports) {
|
||||
// Find exported classes, functions, and vars
|
||||
if (
|
||||
(
|
||||
// Exported class
|
||||
ts.isClassDeclaration(node)
|
||||
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
|
||||
&& node.name
|
||||
) || (
|
||||
// Exported function
|
||||
ts.isFunctionDeclaration(node)
|
||||
&& ts.isSourceFile(node.parent)
|
||||
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
|
||||
&& node.name && node.body // On named function and not on the overload
|
||||
) || (
|
||||
// Exported variable
|
||||
ts.isVariableDeclaration(node)
|
||||
&& hasModifier(node.parent.parent, ts.SyntaxKind.ExportKeyword) // Variable statement is exported
|
||||
&& ts.isSourceFile(node.parent.parent.parent)
|
||||
)
|
||||
|
||||
// Disabled for now because we need to figure out how to handle
|
||||
// enums that are used in monaco or extHost interfaces.
|
||||
/* || (
|
||||
// Exported enum
|
||||
ts.isEnumDeclaration(node)
|
||||
&& ts.isSourceFile(node.parent)
|
||||
&& hasModifier(node, ts.SyntaxKind.ExportKeyword)
|
||||
&& !hasModifier(node, ts.SyntaxKind.ConstKeyword) // Don't bother mangling const enums because these are inlined
|
||||
&& node.name
|
||||
*/
|
||||
) {
|
||||
if (isInAmbientContext(node)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.allExportedSymbols.add(new DeclarationData(node.getSourceFile().fileName, node, this.service));
|
||||
}
|
||||
}
|
||||
|
||||
ts.forEachChild(node, visit);
|
||||
};
|
||||
|
||||
@@ -367,7 +487,7 @@ export class Mangler {
|
||||
ts.forEachChild(file, visit);
|
||||
}
|
||||
}
|
||||
this.log(`Done collecting classes: ${this.allClassDataByKey.size}`);
|
||||
this.log(`Done collecting. Classes: ${this.allClassDataByKey.size}. Exported symbols: ${this.allExportedSymbols.size}`);
|
||||
|
||||
|
||||
// STEP: connect sub and super-types
|
||||
@@ -433,9 +553,11 @@ export class Mangler {
|
||||
for (const data of this.allClassDataByKey.values()) {
|
||||
ClassData.fillInReplacement(data);
|
||||
}
|
||||
this.log(`Done creating replacements`);
|
||||
this.log(`Done creating class replacements`);
|
||||
|
||||
// STEP: prepare rename edits
|
||||
this.log(`Starting prepare rename edits`);
|
||||
|
||||
type Edit = { newText: string; offset: number; length: number };
|
||||
const editsByFile = new Map<string, Edit[]>();
|
||||
|
||||
@@ -447,9 +569,24 @@ export class Mangler {
|
||||
edits.push(edit);
|
||||
}
|
||||
};
|
||||
const appendRename = (newText: string, loc: ts.RenameLocation) => {
|
||||
appendEdit(loc.fileName, {
|
||||
newText: (loc.prefixText || '') + newText + (loc.suffixText || ''),
|
||||
offset: loc.textSpan.start,
|
||||
length: loc.textSpan.length
|
||||
});
|
||||
};
|
||||
|
||||
type RenameFn = (projectName: string, fileName: string, pos: number) => ts.RenameLocation[];
|
||||
|
||||
const renameResults: Array<Promise<{ readonly newName: string; readonly locations: readonly ts.RenameLocation[] }>> = [];
|
||||
|
||||
const queueRename = (fileName: string, pos: number, newName: string) => {
|
||||
renameResults.push(Promise.resolve(this.renameWorkerPool.exec<RenameFn>('findRenameLocations', [this.projectPath, fileName, pos]))
|
||||
.then((locations) => ({ newName, locations })));
|
||||
};
|
||||
|
||||
for (const data of this.allClassDataByKey.values()) {
|
||||
|
||||
if (hasModifier(data.node, ts.SyntaxKind.DeclareKeyword)) {
|
||||
continue;
|
||||
}
|
||||
@@ -469,18 +606,39 @@ export class Mangler {
|
||||
parent = parent.parent;
|
||||
}
|
||||
|
||||
const newText = data.lookupShortName(name);
|
||||
const locations = this.service.findRenameLocations(data.fileName, info.pos, false, false, true) ?? [];
|
||||
for (const loc of locations) {
|
||||
appendEdit(loc.fileName, {
|
||||
newText: (loc.prefixText || '') + newText + (loc.suffixText || ''),
|
||||
offset: loc.textSpan.start,
|
||||
length: loc.textSpan.length
|
||||
});
|
||||
}
|
||||
const newName = data.lookupShortName(name);
|
||||
queueRename(data.fileName, info.pos, newName);
|
||||
}
|
||||
}
|
||||
|
||||
for (const data of this.allExportedSymbols.values()) {
|
||||
if (data.fileName.endsWith('.d.ts')
|
||||
|| skippedExportMangledProjects.some(proj => data.fileName.includes(proj))
|
||||
|| skippedExportMangledFiles.some(file => data.fileName.endsWith(file + '.ts'))
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!data.shouldMangle(data.replacementName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newText = data.replacementName;
|
||||
for (const { fileName, offset } of data.locations) {
|
||||
queueRename(fileName, offset, newText);
|
||||
}
|
||||
}
|
||||
|
||||
await Promise.all(renameResults).then((result) => {
|
||||
for (const { newName, locations } of result) {
|
||||
for (const loc of locations) {
|
||||
appendRename(newName, loc);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
await this.renameWorkerPool.terminate();
|
||||
|
||||
this.log(`Done preparing edits: ${editsByFile.size} files`);
|
||||
|
||||
// STEP: apply all rename edits (per file)
|
||||
@@ -579,17 +737,32 @@ function hasModifier(node: ts.Node, kind: ts.SyntaxKind) {
|
||||
return Boolean(modifiers?.find(mode => mode.kind === kind));
|
||||
}
|
||||
|
||||
function isInAmbientContext(node: ts.Node): boolean {
|
||||
for (let p = node.parent; p; p = p.parent) {
|
||||
if (ts.isModuleDeclaration(p)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function normalize(path: string): string {
|
||||
return path.replace(/\\/g, '/');
|
||||
}
|
||||
|
||||
async function _run() {
|
||||
|
||||
const projectPath = path.join(__dirname, '../../src/tsconfig.json');
|
||||
const projectBase = path.dirname(projectPath);
|
||||
const root = path.join(__dirname, '..', '..', '..');
|
||||
const projectBase = path.join(root, 'src');
|
||||
const projectPath = path.join(projectBase, 'tsconfig.json');
|
||||
const newProjectBase = path.join(path.dirname(projectBase), path.basename(projectBase) + '2');
|
||||
|
||||
for await (const [fileName, contents] of new Mangler(projectPath, console.log).computeNewFileContents(new Set(['saveState']))) {
|
||||
fs.cpSync(projectBase, newProjectBase, { recursive: true });
|
||||
|
||||
const mangler = new Mangler(projectPath, console.log, {
|
||||
mangleExports: true,
|
||||
manglePrivateFields: true,
|
||||
});
|
||||
for (const [fileName, contents] of await mangler.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);
|
||||
@@ -0,0 +1,20 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const ts = require("typescript");
|
||||
const workerpool = require("workerpool");
|
||||
const staticLanguageServiceHost_1 = require("./staticLanguageServiceHost");
|
||||
let service; // = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
|
||||
function findRenameLocations(projectPath, fileName, position) {
|
||||
if (!service) {
|
||||
service = ts.createLanguageService(new staticLanguageServiceHost_1.StaticLanguageServiceHost(projectPath));
|
||||
}
|
||||
return service.findRenameLocations(fileName, position, false, false, true) ?? [];
|
||||
}
|
||||
workerpool.worker({
|
||||
findRenameLocations
|
||||
});
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVuYW1lV29ya2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsicmVuYW1lV29ya2VyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7QUFFaEcsaUNBQWlDO0FBQ2pDLHlDQUF5QztBQUN6QywyRUFBd0U7QUFFeEUsSUFBSSxPQUF1QyxDQUFDLENBQUEsMEVBQTBFO0FBRXRILFNBQVMsbUJBQW1CLENBQzNCLFdBQW1CLEVBQ25CLFFBQWdCLEVBQ2hCLFFBQWdCO0lBRWhCLElBQUksQ0FBQyxPQUFPLEVBQUU7UUFDYixPQUFPLEdBQUcsRUFBRSxDQUFDLHFCQUFxQixDQUFDLElBQUkscURBQXlCLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQztLQUMvRTtJQUVELE9BQU8sT0FBTyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxRQUFRLEVBQUUsS0FBSyxFQUFFLEtBQUssRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDbEYsQ0FBQztBQUVELFVBQVUsQ0FBQyxNQUFNLENBQUM7SUFDakIsbUJBQW1CO0NBQ25CLENBQUMsQ0FBQyJ9
|
||||
@@ -0,0 +1,26 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as workerpool from 'workerpool';
|
||||
import { StaticLanguageServiceHost } from './staticLanguageServiceHost';
|
||||
|
||||
let service: ts.LanguageService | undefined;// = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
|
||||
|
||||
function findRenameLocations(
|
||||
projectPath: string,
|
||||
fileName: string,
|
||||
position: number,
|
||||
): readonly ts.RenameLocation[] {
|
||||
if (!service) {
|
||||
service = ts.createLanguageService(new StaticLanguageServiceHost(projectPath));
|
||||
}
|
||||
|
||||
return service.findRenameLocations(fileName, position, false, false, true) ?? [];
|
||||
}
|
||||
|
||||
workerpool.worker({
|
||||
findRenameLocations
|
||||
});
|
||||
@@ -0,0 +1,65 @@
|
||||
"use strict";
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.StaticLanguageServiceHost = void 0;
|
||||
const ts = require("typescript");
|
||||
const path = require("path");
|
||||
class StaticLanguageServiceHost {
|
||||
projectPath;
|
||||
_cmdLine;
|
||||
_scriptSnapshots = new Map();
|
||||
constructor(projectPath) {
|
||||
this.projectPath = projectPath;
|
||||
const existingOptions = {};
|
||||
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
|
||||
if (parsed.error) {
|
||||
throw parsed.error;
|
||||
}
|
||||
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
|
||||
if (this._cmdLine.errors.length > 0) {
|
||||
throw parsed.error;
|
||||
}
|
||||
}
|
||||
getCompilationSettings() {
|
||||
return this._cmdLine.options;
|
||||
}
|
||||
getScriptFileNames() {
|
||||
return this._cmdLine.fileNames;
|
||||
}
|
||||
getScriptVersion(_fileName) {
|
||||
return '1';
|
||||
}
|
||||
getProjectVersion() {
|
||||
return '1';
|
||||
}
|
||||
getScriptSnapshot(fileName) {
|
||||
let result = this._scriptSnapshots.get(fileName);
|
||||
if (result === undefined) {
|
||||
const content = ts.sys.readFile(fileName);
|
||||
if (content === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
result = ts.ScriptSnapshot.fromString(content);
|
||||
this._scriptSnapshots.set(fileName, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
getCurrentDirectory() {
|
||||
return path.dirname(this.projectPath);
|
||||
}
|
||||
getDefaultLibFileName(options) {
|
||||
return ts.getDefaultLibFilePath(options);
|
||||
}
|
||||
directoryExists = ts.sys.directoryExists;
|
||||
getDirectories = ts.sys.getDirectories;
|
||||
fileExists = ts.sys.fileExists;
|
||||
readFile = ts.sys.readFile;
|
||||
readDirectory = ts.sys.readDirectory;
|
||||
// this is necessary to make source references work.
|
||||
realpath = ts.sys.realpath;
|
||||
}
|
||||
exports.StaticLanguageServiceHost = StaticLanguageServiceHost;
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdGljTGFuZ3VhZ2VTZXJ2aWNlSG9zdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInN0YXRpY0xhbmd1YWdlU2VydmljZUhvc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Z0dBR2dHOzs7QUFFaEcsaUNBQWlDO0FBQ2pDLDZCQUE2QjtBQUU3QixNQUFhLHlCQUF5QjtJQUtoQjtJQUhKLFFBQVEsQ0FBdUI7SUFDL0IsZ0JBQWdCLEdBQW9DLElBQUksR0FBRyxFQUFFLENBQUM7SUFFL0UsWUFBcUIsV0FBbUI7UUFBbkIsZ0JBQVcsR0FBWCxXQUFXLENBQVE7UUFDdkMsTUFBTSxlQUFlLEdBQWdDLEVBQUUsQ0FBQztRQUN4RCxNQUFNLE1BQU0sR0FBRyxFQUFFLENBQUMsY0FBYyxDQUFDLFdBQVcsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQy9ELElBQUksTUFBTSxDQUFDLEtBQUssRUFBRTtZQUNqQixNQUFNLE1BQU0sQ0FBQyxLQUFLLENBQUM7U0FDbkI7UUFDRCxJQUFJLENBQUMsUUFBUSxHQUFHLEVBQUUsQ0FBQywwQkFBMEIsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLEVBQUUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxXQUFXLENBQUMsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUNqSCxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUU7WUFDcEMsTUFBTSxNQUFNLENBQUMsS0FBSyxDQUFDO1NBQ25CO0lBQ0YsQ0FBQztJQUNELHNCQUFzQjtRQUNyQixPQUFPLElBQUksQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO0lBQzlCLENBQUM7SUFDRCxrQkFBa0I7UUFDakIsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLFNBQVMsQ0FBQztJQUNoQyxDQUFDO0lBQ0QsZ0JBQWdCLENBQUMsU0FBaUI7UUFDakMsT0FBTyxHQUFHLENBQUM7SUFDWixDQUFDO0lBQ0QsaUJBQWlCO1FBQ2hCLE9BQU8sR0FBRyxDQUFDO0lBQ1osQ0FBQztJQUNELGlCQUFpQixDQUFDLFFBQWdCO1FBQ2pDLElBQUksTUFBTSxHQUFtQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQ2pGLElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRTtZQUN6QixNQUFNLE9BQU8sR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMxQyxJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUU7Z0JBQzFCLE9BQU8sU0FBUyxDQUFDO2FBQ2pCO1lBQ0QsTUFBTSxHQUFHLEVBQUUsQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQy9DLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsUUFBUSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1NBQzVDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDZixDQUFDO0lBQ0QsbUJBQW1CO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUNELHFCQUFxQixDQUFDLE9BQTJCO1FBQ2hELE9BQU8sRUFBRSxDQUFDLHFCQUFxQixDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLENBQUM7SUFDRCxlQUFlLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxlQUFlLENBQUM7SUFDekMsY0FBYyxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDO0lBQ3ZDLFVBQVUsR0FBRyxFQUFFLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQztJQUMvQixRQUFRLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7SUFDM0IsYUFBYSxHQUFHLEVBQUUsQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDO0lBQ3JDLG9EQUFvRDtJQUNwRCxRQUFRLEdBQUcsRUFBRSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUM7Q0FDM0I7QUFyREQsOERBcURDIn0=
|
||||
@@ -0,0 +1,62 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as path from 'path';
|
||||
|
||||
export class StaticLanguageServiceHost implements ts.LanguageServiceHost {
|
||||
|
||||
private readonly _cmdLine: ts.ParsedCommandLine;
|
||||
private readonly _scriptSnapshots: Map<string, ts.IScriptSnapshot> = new Map();
|
||||
|
||||
constructor(readonly projectPath: string) {
|
||||
const existingOptions: Partial<ts.CompilerOptions> = {};
|
||||
const parsed = ts.readConfigFile(projectPath, ts.sys.readFile);
|
||||
if (parsed.error) {
|
||||
throw parsed.error;
|
||||
}
|
||||
this._cmdLine = ts.parseJsonConfigFileContent(parsed.config, ts.sys, path.dirname(projectPath), existingOptions);
|
||||
if (this._cmdLine.errors.length > 0) {
|
||||
throw parsed.error;
|
||||
}
|
||||
}
|
||||
getCompilationSettings(): ts.CompilerOptions {
|
||||
return this._cmdLine.options;
|
||||
}
|
||||
getScriptFileNames(): string[] {
|
||||
return this._cmdLine.fileNames;
|
||||
}
|
||||
getScriptVersion(_fileName: string): string {
|
||||
return '1';
|
||||
}
|
||||
getProjectVersion(): string {
|
||||
return '1';
|
||||
}
|
||||
getScriptSnapshot(fileName: string): ts.IScriptSnapshot | undefined {
|
||||
let result: ts.IScriptSnapshot | undefined = this._scriptSnapshots.get(fileName);
|
||||
if (result === undefined) {
|
||||
const content = ts.sys.readFile(fileName);
|
||||
if (content === undefined) {
|
||||
return undefined;
|
||||
}
|
||||
result = ts.ScriptSnapshot.fromString(content);
|
||||
this._scriptSnapshots.set(fileName, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
getCurrentDirectory(): string {
|
||||
return path.dirname(this.projectPath);
|
||||
}
|
||||
getDefaultLibFileName(options: ts.CompilerOptions): string {
|
||||
return ts.getDefaultLibFilePath(options);
|
||||
}
|
||||
directoryExists = ts.sys.directoryExists;
|
||||
getDirectories = ts.sys.getDirectories;
|
||||
fileExists = ts.sys.fileExists;
|
||||
readFile = ts.sys.readFile;
|
||||
readDirectory = ts.sys.readDirectory;
|
||||
// this is necessary to make source references work.
|
||||
realpath = ts.sys.realpath;
|
||||
}
|
||||
+169
-22
File diff suppressed because one or more lines are too long
@@ -63,9 +63,10 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'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.8)',
|
||||
'libc6 (>= 2.9)',
|
||||
'libcairo2 (>= 1.6.0)',
|
||||
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
|
||||
@@ -73,7 +74,7 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'libdrm2 (>= 2.4.60)',
|
||||
'libexpat1 (>= 2.0.1)',
|
||||
'libgbm1 (>= 17.1.0~rc2)',
|
||||
'libglib2.0-0 (>= 2.16.0)',
|
||||
'libglib2.0-0 (>= 2.12.0)',
|
||||
'libglib2.0-0 (>= 2.39.4)',
|
||||
'libgtk-3-0 (>= 3.9.10)',
|
||||
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
|
||||
@@ -82,7 +83,6 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'libnss3 (>= 3.26)',
|
||||
'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)',
|
||||
@@ -105,14 +105,13 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'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)',
|
||||
'libexpat1 (>= 2.0.1)',
|
||||
'libgbm1 (>= 17.1.0~rc2)',
|
||||
'libglib2.0-0 (>= 2.16.0)',
|
||||
'libglib2.0-0 (>= 2.12.0)',
|
||||
'libglib2.0-0 (>= 2.39.4)',
|
||||
'libgtk-3-0 (>= 3.9.10)',
|
||||
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
|
||||
@@ -121,7 +120,6 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'libnss3 (>= 3.26)',
|
||||
'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)',
|
||||
@@ -138,4 +136,4 @@ exports.referenceGeneratedDepsByArch = {
|
||||
'xdg-utils (>= 1.0.2)'
|
||||
]
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsa0JBQWtCO1FBQ2xCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsZ0JBQWdCO1FBQ2hCLGdCQUFnQjtRQUNoQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHlCQUF5QjtRQUN6QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6Qix1QkFBdUI7UUFDdkIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLGlCQUFpQjtRQUNqQixzQkFBc0I7UUFDdEIsc0RBQXNEO1FBQ3RELHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsc0JBQXNCO1FBQ3RCLHlCQUF5QjtRQUN6QiwwQkFBMEI7UUFDMUIsMEJBQTBCO1FBQzFCLHdCQUF3QjtRQUN4QixxQ0FBcUM7UUFDckMsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsNEJBQTRCO1FBQzVCLHlCQUF5QjtRQUN6Qix1QkFBdUI7UUFDdkIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtDQUNELENBQUMifQ==
|
||||
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGVwLWxpc3RzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiZGVwLWxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7QUFBQTs7O2dHQUdnRzs7O0FBRWhHLGtIQUFrSDtBQUNsSCw0REFBNEQ7QUFDL0MsUUFBQSxjQUFjLEdBQUc7SUFDN0IsaUJBQWlCO0lBQ2pCLHFDQUFxQztJQUNyQyxtQkFBbUI7SUFDbkIsc0RBQXNEO0lBQ3RELHNCQUFzQixDQUFDLGlCQUFpQjtDQUN4QyxDQUFDO0FBRUYsb0hBQW9IO0FBQ3BILDBDQUEwQztBQUMxQyw4REFBOEQ7QUFDakQsUUFBQSxlQUFlLEdBQUc7SUFDOUIsWUFBWSxDQUFDLHlFQUF5RTtDQUN0RixDQUFDO0FBRVcsUUFBQSw0QkFBNEIsR0FBRztJQUMzQyxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsa0JBQWtCO1FBQ2xCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQseUJBQXlCO1FBQ3pCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7SUFDRCxPQUFPLEVBQUU7UUFDUixpQkFBaUI7UUFDakIsd0JBQXdCO1FBQ3hCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsMkJBQTJCO1FBQzNCLGlCQUFpQjtRQUNqQixpQkFBaUI7UUFDakIsZ0JBQWdCO1FBQ2hCLGdCQUFnQjtRQUNoQixnQkFBZ0I7UUFDaEIsc0JBQXNCO1FBQ3RCLHNEQUFzRDtRQUN0RCx5QkFBeUI7UUFDekIscUJBQXFCO1FBQ3JCLHNCQUFzQjtRQUN0Qix5QkFBeUI7UUFDekIsMEJBQTBCO1FBQzFCLDBCQUEwQjtRQUMxQix3QkFBd0I7UUFDeEIscUNBQXFDO1FBQ3JDLHdCQUF3QjtRQUN4QixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1Qix5QkFBeUI7UUFDekIsbUJBQW1CO1FBQ25CLHFCQUFxQjtRQUNyQixtQkFBbUI7UUFDbkIsVUFBVTtRQUNWLDBCQUEwQjtRQUMxQixvQkFBb0I7UUFDcEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QixVQUFVO1FBQ1YsWUFBWTtRQUNaLDBCQUEwQjtRQUMxQixhQUFhO1FBQ2IsWUFBWTtRQUNaLHNCQUFzQjtLQUN0QjtJQUNELE9BQU8sRUFBRTtRQUNSLGlCQUFpQjtRQUNqQix3QkFBd0I7UUFDeEIsK0JBQStCO1FBQy9CLHdCQUF3QjtRQUN4QiwyQkFBMkI7UUFDM0IsaUJBQWlCO1FBQ2pCLHNCQUFzQjtRQUN0QixzREFBc0Q7UUFDdEQsd0JBQXdCO1FBQ3hCLHFCQUFxQjtRQUNyQixzQkFBc0I7UUFDdEIseUJBQXlCO1FBQ3pCLDBCQUEwQjtRQUMxQiwwQkFBMEI7UUFDMUIsd0JBQXdCO1FBQ3hCLHFDQUFxQztRQUNyQyx3QkFBd0I7UUFDeEIscUJBQXFCO1FBQ3JCLG1CQUFtQjtRQUNuQiw0QkFBNEI7UUFDNUIseUJBQXlCO1FBQ3pCLG1CQUFtQjtRQUNuQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLFVBQVU7UUFDViwwQkFBMEI7UUFDMUIsb0JBQW9CO1FBQ3BCLCtCQUErQjtRQUMvQix3QkFBd0I7UUFDeEIsVUFBVTtRQUNWLFlBQVk7UUFDWiwwQkFBMEI7UUFDMUIsYUFBYTtRQUNiLFlBQVk7UUFDWixzQkFBc0I7S0FDdEI7Q0FDRCxDQUFDIn0=
|
||||
@@ -63,9 +63,10 @@ export const referenceGeneratedDepsByArch = {
|
||||
'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.8)',
|
||||
'libc6 (>= 2.9)',
|
||||
'libcairo2 (>= 1.6.0)',
|
||||
'libcurl3-gnutls | libcurl3-nss | libcurl4 | libcurl3',
|
||||
@@ -73,7 +74,7 @@ export const referenceGeneratedDepsByArch = {
|
||||
'libdrm2 (>= 2.4.60)',
|
||||
'libexpat1 (>= 2.0.1)',
|
||||
'libgbm1 (>= 17.1.0~rc2)',
|
||||
'libglib2.0-0 (>= 2.16.0)',
|
||||
'libglib2.0-0 (>= 2.12.0)',
|
||||
'libglib2.0-0 (>= 2.39.4)',
|
||||
'libgtk-3-0 (>= 3.9.10)',
|
||||
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
|
||||
@@ -82,7 +83,6 @@ export const referenceGeneratedDepsByArch = {
|
||||
'libnss3 (>= 3.26)',
|
||||
'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)',
|
||||
@@ -105,14 +105,13 @@ export const referenceGeneratedDepsByArch = {
|
||||
'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)',
|
||||
'libexpat1 (>= 2.0.1)',
|
||||
'libgbm1 (>= 17.1.0~rc2)',
|
||||
'libglib2.0-0 (>= 2.16.0)',
|
||||
'libglib2.0-0 (>= 2.12.0)',
|
||||
'libglib2.0-0 (>= 2.39.4)',
|
||||
'libgtk-3-0 (>= 3.9.10)',
|
||||
'libgtk-3-0 (>= 3.9.10) | libgtk-4-1',
|
||||
@@ -121,7 +120,6 @@ export const referenceGeneratedDepsByArch = {
|
||||
'libnss3 (>= 3.26)',
|
||||
'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)',
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -126,7 +126,6 @@ export const referenceGeneratedDepsByArch = {
|
||||
'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)',
|
||||
@@ -220,7 +219,6 @@ export const referenceGeneratedDepsByArch = {
|
||||
'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)',
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
"@types/through2": "^2.0.36",
|
||||
"@types/tmp": "^0.2.1",
|
||||
"@types/underscore": "^1.8.9",
|
||||
"@types/workerpool": "^6.4.0",
|
||||
"@types/xml2js": "0.0.33",
|
||||
"@vscode/iconv-lite-umd": "0.7.0",
|
||||
"@vscode/vsce": "^2.16.0",
|
||||
@@ -70,5 +71,8 @@
|
||||
"tree-sitter": "https://github.com/joaomoreno/node-tree-sitter/releases/download/v0.20.0/tree-sitter-0.20.0.tgz",
|
||||
"tree-sitter-typescript": "^0.20.1",
|
||||
"vscode-gulp-watch": "^5.0.3"
|
||||
},
|
||||
"dependencies": {
|
||||
"workerpool": "^6.4.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -646,6 +646,13 @@
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/workerpool@^6.4.0":
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@types/workerpool/-/workerpool-6.4.0.tgz#c79292915dd08350d10e78e74687b6f401f270b8"
|
||||
integrity sha512-SIF2/169pDsLKeM8GQGHkOFifGalDbZgiBSaLUnnlVSRsAOenkAvQ6h4uhV2W+PZZczS+8LQxACwNkSykdT91A==
|
||||
dependencies:
|
||||
"@types/node" "*"
|
||||
|
||||
"@types/xml2js@0.0.33":
|
||||
version "0.0.33"
|
||||
resolved "https://registry.yarnpkg.com/@types/xml2js/-/xml2js-0.0.33.tgz#20c5dd6460245284d64a55690015b95e409fb7de"
|
||||
@@ -3017,6 +3024,11 @@ wide-align@^1.1.0:
|
||||
dependencies:
|
||||
string-width "^1.0.2 || 2 || 3 || 4"
|
||||
|
||||
workerpool@^6.4.0:
|
||||
version "6.4.0"
|
||||
resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.4.0.tgz#f8d5cfb45fde32fa3b7af72ad617c3369567a462"
|
||||
integrity sha512-i3KR1mQMNwY2wx20ozq2EjISGtQWDIfV56We+yGJ5yDs8jTwQiLLaqHlkBHITlCuJnYlVRmXegxFxZg7gqI++A==
|
||||
|
||||
wrappy@1:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
|
||||
+46
-1
@@ -20,7 +20,7 @@ use async_trait::async_trait;
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use gethostname::gethostname;
|
||||
use serde::{de::DeserializeOwned, Deserialize, Serialize};
|
||||
use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc};
|
||||
use std::{cell::Cell, fmt::Display, path::PathBuf, sync::Arc, thread};
|
||||
use tokio::time::sleep;
|
||||
use tunnels::{
|
||||
contracts::PROD_FIRST_PARTY_APP_ID,
|
||||
@@ -210,6 +210,48 @@ const KEYCHAIN_ENTRY_LIMIT: usize = 128 * 1024;
|
||||
|
||||
const CONTINUE_MARKER: &str = "<MORE>";
|
||||
|
||||
/// Implementation that wraps the KeyringStorage on Linux to avoid
|
||||
/// https://github.com/hwchen/keyring-rs/issues/132
|
||||
struct ThreadKeyringStorage {
|
||||
s: Option<KeyringStorage>,
|
||||
}
|
||||
|
||||
impl ThreadKeyringStorage {
|
||||
fn thread_op<R, Fn>(&mut self, f: Fn) -> R
|
||||
where
|
||||
Fn: 'static + Send + FnOnce(&mut KeyringStorage) -> R,
|
||||
R: 'static + Send,
|
||||
{
|
||||
let mut s = self.s.take().unwrap();
|
||||
let handler = thread::spawn(move || (f(&mut s), s));
|
||||
let (r, s) = handler.join().unwrap();
|
||||
self.s = Some(s);
|
||||
r
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for ThreadKeyringStorage {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
s: Some(KeyringStorage::default()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StorageImplementation for ThreadKeyringStorage {
|
||||
fn read(&mut self) -> Result<Option<StoredCredential>, WrappedError> {
|
||||
self.thread_op(|s| s.read())
|
||||
}
|
||||
|
||||
fn store(&mut self, value: StoredCredential) -> Result<(), WrappedError> {
|
||||
self.thread_op(move |s| s.store(value))
|
||||
}
|
||||
|
||||
fn clear(&mut self) -> Result<(), WrappedError> {
|
||||
self.thread_op(|s| s.clear())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct KeyringStorage {
|
||||
// keywring storage can be split into multiple entries due to entry length limits
|
||||
@@ -325,7 +367,10 @@ impl Auth {
|
||||
return op(s);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
let mut keyring_storage = KeyringStorage::default();
|
||||
#[cfg(target_os = "linux")]
|
||||
let mut keyring_storage = ThreadKeyringStorage::default();
|
||||
let mut file_storage = FileStorage(PersistedState::new(self.file_storage_path.clone()));
|
||||
|
||||
let keyring_storage_result = match std::env::var("VSCODE_CLI_USE_FILE_KEYCHAIN") {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { promises as fs } from 'fs';
|
||||
import { createServer, Server } from 'net';
|
||||
import { dirname } from 'path';
|
||||
import * as vscode from 'vscode';
|
||||
|
||||
const enum State {
|
||||
@@ -72,8 +73,7 @@ export function activate(context: vscode.ExtensionContext): void {
|
||||
e.affectsConfiguration(`${SETTING_SECTION}.${SETTING_STATE}`) ||
|
||||
[...SETTINGS_CAUSE_REFRESH].some(setting => e.affectsConfiguration(setting))
|
||||
) {
|
||||
updateAutoAttach(State.Disabled);
|
||||
updateAutoAttach(readCurrentState());
|
||||
refreshAutoAttachVars();
|
||||
}
|
||||
}),
|
||||
);
|
||||
@@ -85,6 +85,11 @@ export async function deactivate(): Promise<void> {
|
||||
await destroyAttachServer();
|
||||
}
|
||||
|
||||
function refreshAutoAttachVars() {
|
||||
updateAutoAttach(State.Disabled);
|
||||
updateAutoAttach(readCurrentState());
|
||||
}
|
||||
|
||||
function getDefaultScope(info: ReturnType<vscode.WorkspaceConfiguration['inspect']>) {
|
||||
if (!info) {
|
||||
return vscode.ConfigurationTarget.Global;
|
||||
@@ -204,8 +209,22 @@ async function createAttachServer(context: vscode.ExtensionContext) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
server = createServerInner(ipcAddress).catch(err => {
|
||||
console.error(err);
|
||||
server = createServerInner(ipcAddress).catch(async err => {
|
||||
console.error('[debug-auto-launch] Error creating auto attach server: ', err);
|
||||
|
||||
if (process.platform !== 'win32') {
|
||||
// On macOS, and perhaps some Linux distros, the temporary directory can
|
||||
// sometimes change. If it looks like that's the cause of a listener
|
||||
// error, automatically refresh the auto attach vars.
|
||||
try {
|
||||
await fs.access(dirname(ipcAddress));
|
||||
} catch {
|
||||
console.error('[debug-auto-launch] Refreshing variables from error');
|
||||
refreshAutoAttachVars();
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
|
||||
/**
|
||||
* @fileoverview Common build script for extension scripts used in in webviews.
|
||||
*/
|
||||
|
||||
const path = require('path');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
/**
|
||||
* @typedef {Partial<import('esbuild').BuildOptions> & {
|
||||
* entryPoints: string[] | Record<string, string> | { in: string, out: string }[];
|
||||
* outdir: string;
|
||||
* }} BuildOptions
|
||||
*/
|
||||
|
||||
/**
|
||||
* Build the source code once using esbuild.
|
||||
*
|
||||
* @param {BuildOptions} options
|
||||
* @param {(outDir: string) => unknown} [didBuild]
|
||||
*/
|
||||
async function build(options, didBuild) {
|
||||
await esbuild.build({
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
...options,
|
||||
});
|
||||
|
||||
await didBuild?.(options.outdir);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the source code once using esbuild, logging errors instead of throwing.
|
||||
*
|
||||
* @param {BuildOptions} options
|
||||
* @param {(outDir: string) => unknown} [didBuild]
|
||||
*/
|
||||
async function tryBuild(options, didBuild) {
|
||||
try {
|
||||
await build(options, didBuild);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {{
|
||||
* srcDir: string;
|
||||
* outdir: string;
|
||||
* entryPoints: string[] | Record<string, string> | { in: string, out: string }[];
|
||||
* additionalOptions?: Partial<import('esbuild').BuildOptions>
|
||||
* }} config
|
||||
* @param {string[]} args
|
||||
* @param {(outDir: string) => unknown} [didBuild]
|
||||
*/
|
||||
module.exports.run = function (config, args, didBuild) {
|
||||
let outdir = config.outdir;
|
||||
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
const outputRoot = args[outputRootIndex + 1];
|
||||
const outputDirName = path.basename(outdir);
|
||||
outdir = path.join(outputRoot, outputDirName);
|
||||
}
|
||||
|
||||
/** @type {BuildOptions} */
|
||||
const resolvedOptions = {
|
||||
entryPoints: config.entryPoints,
|
||||
outdir,
|
||||
...(config.additionalOptions || {}),
|
||||
};
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
if (isWatch) {
|
||||
tryBuild(resolvedOptions);
|
||||
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(config.srcDir, () => tryBuild(resolvedOptions, didBuild));
|
||||
} else {
|
||||
return build(resolvedOptions, didBuild).catch(() => process.exit(1));
|
||||
}
|
||||
};
|
||||
@@ -88,7 +88,7 @@
|
||||
"command": "git.reopenClosedRepositories",
|
||||
"title": "%command.reopenClosedRepositories%",
|
||||
"category": "Git",
|
||||
"enablement": "!operationInProgress && git.ClosedRepositoryCount != 0"
|
||||
"enablement": "!operationInProgress && git.closedRepositoryCount != 0"
|
||||
},
|
||||
{
|
||||
"command": "git.close",
|
||||
|
||||
@@ -196,9 +196,9 @@ class FetchAllRemotesItem implements QuickPickItem {
|
||||
}
|
||||
|
||||
class RepositoryItem implements QuickPickItem {
|
||||
get label(): string {
|
||||
return `$(repo) ${this.path}`;
|
||||
}
|
||||
get label(): string { return `$(repo) ${getRepositoryLabel(this.path)}`; }
|
||||
|
||||
get description(): string { return this.path; }
|
||||
|
||||
constructor(public readonly path: string) { }
|
||||
}
|
||||
@@ -358,6 +358,15 @@ function getCheckoutProcessor(repository: Repository, type: string): CheckoutPro
|
||||
return undefined;
|
||||
}
|
||||
|
||||
function getRepositoryLabel(repositoryRoot: string): string {
|
||||
const workspaceFolder = workspace.getWorkspaceFolder(Uri.file(repositoryRoot));
|
||||
return workspaceFolder?.uri.toString() === repositoryRoot ? workspaceFolder.name : path.basename(repositoryRoot);
|
||||
}
|
||||
|
||||
function compareRepositoryLabel(repositoryRoot1: string, repositoryRoot2: string): number {
|
||||
return getRepositoryLabel(repositoryRoot1).localeCompare(getRepositoryLabel(repositoryRoot2));
|
||||
}
|
||||
|
||||
function sanitizeBranchName(name: string, whitespaceChar: string): string {
|
||||
return name ? name.trim().replace(/^-+/, '').replace(/^\.|\/\.|\.\.|~|\^|:|\/$|\.lock$|\.lock\/|\\|\*|\s|^\s*$|\.$|\[|\]$/g, whitespaceChar) : name;
|
||||
}
|
||||
@@ -896,7 +905,8 @@ export class CommandCenter {
|
||||
|
||||
const allRepositoriesLabel = l10n.t('All Repositories');
|
||||
const allRepositoriesQuickPickItem: QuickPickItem = { label: allRepositoriesLabel };
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = this.model.closedRepositories.sort().map(r => new RepositoryItem(r));
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = this.model.closedRepositories
|
||||
.sort(compareRepositoryLabel).map(r => new RepositoryItem(r));
|
||||
|
||||
const items = this.model.closedRepositories.length === 1 ? [...repositoriesQuickPickItems] :
|
||||
[...repositoriesQuickPickItems, { label: '', kind: QuickPickItemKind.Separator }, allRepositoriesQuickPickItem];
|
||||
@@ -3459,9 +3469,10 @@ export class CommandCenter {
|
||||
|
||||
const allRepositoriesLabel = l10n.t('All Repositories');
|
||||
const allRepositoriesQuickPickItem: QuickPickItem = { label: allRepositoriesLabel };
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = Array.from(this.model.parentRepositories.keys()).sort().map(r => new RepositoryItem(r));
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = this.model.parentRepositories
|
||||
.sort(compareRepositoryLabel).map(r => new RepositoryItem(r));
|
||||
|
||||
const items = this.model.parentRepositories.size === 1 ? [...repositoriesQuickPickItems] :
|
||||
const items = this.model.parentRepositories.length === 1 ? [...repositoriesQuickPickItems] :
|
||||
[...repositoriesQuickPickItems, { label: '', kind: QuickPickItemKind.Separator }, allRepositoriesQuickPickItem];
|
||||
|
||||
const repositoryItem = await window.showQuickPick(items, { title, placeHolder });
|
||||
@@ -3471,7 +3482,7 @@ export class CommandCenter {
|
||||
|
||||
if (repositoryItem === allRepositoriesQuickPickItem) {
|
||||
// All Repositories
|
||||
parentRepositories.push(...this.model.parentRepositories.keys());
|
||||
parentRepositories.push(...this.model.parentRepositories);
|
||||
} else {
|
||||
// One Repository
|
||||
parentRepositories.push((repositoryItem as RepositoryItem).path);
|
||||
@@ -3492,9 +3503,10 @@ export class CommandCenter {
|
||||
|
||||
const allRepositoriesLabel = l10n.t('All Repositories');
|
||||
const allRepositoriesQuickPickItem: QuickPickItem = { label: allRepositoriesLabel };
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = Array.from(this.model.unsafeRepositories.keys()).sort().map(r => new RepositoryItem(r));
|
||||
const repositoriesQuickPickItems: QuickPickItem[] = this.model.unsafeRepositories
|
||||
.sort(compareRepositoryLabel).map(r => new RepositoryItem(r));
|
||||
|
||||
quickpick.items = this.model.unsafeRepositories.size === 1 ? [...repositoriesQuickPickItems] :
|
||||
quickpick.items = this.model.unsafeRepositories.length === 1 ? [...repositoriesQuickPickItems] :
|
||||
[...repositoriesQuickPickItems, { label: '', kind: QuickPickItemKind.Separator }, allRepositoriesQuickPickItem];
|
||||
|
||||
quickpick.show();
|
||||
@@ -3511,7 +3523,7 @@ export class CommandCenter {
|
||||
|
||||
if (repositoryItem.label === allRepositoriesLabel) {
|
||||
// All Repositories
|
||||
unsafeRepositories.push(...this.model.unsafeRepositories.keys());
|
||||
unsafeRepositories.push(...this.model.unsafeRepositories);
|
||||
} else {
|
||||
// One Repository
|
||||
unsafeRepositories.push((repositoryItem as RepositoryItem).path);
|
||||
@@ -3519,11 +3531,11 @@ export class CommandCenter {
|
||||
|
||||
for (const unsafeRepository of unsafeRepositories) {
|
||||
// Mark as Safe
|
||||
await this.git.addSafeDirectory(this.model.unsafeRepositories.get(unsafeRepository)!);
|
||||
await this.git.addSafeDirectory(this.model.getUnsafeRepositoryPath(unsafeRepository)!);
|
||||
|
||||
// Open Repository
|
||||
await this.model.openRepository(unsafeRepository);
|
||||
this.model.unsafeRepositories.delete(unsafeRepository);
|
||||
this.model.deleteUnsafeRepository(unsafeRepository);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,7 +73,7 @@ function findSpecificGit(path: string, onValidate: (path: string) => boolean): P
|
||||
const child = cp.spawn(path, ['--version']);
|
||||
child.stdout.on('data', (b: Buffer) => buffers.push(b));
|
||||
child.on('error', cpErrorHandler(e));
|
||||
child.on('exit', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) }));
|
||||
child.on('close', code => code ? e(new Error('Not found')) : c({ path, version: parseVersion(Buffer.concat(buffers).toString('utf8').trim()) }));
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2021,7 +2021,7 @@ export class Repository {
|
||||
}
|
||||
|
||||
// --find-renames option is only available starting with git 2.18.0
|
||||
if (opts?.similarityThreshold && this._git.compareGitVersionTo('2.18.0') !== -1) {
|
||||
if (opts?.similarityThreshold && opts.similarityThreshold !== 50 && this._git.compareGitVersionTo('2.18.0') !== -1) {
|
||||
args.push(`--find-renames=${opts.similarityThreshold}%`);
|
||||
}
|
||||
|
||||
|
||||
+150
-78
@@ -19,7 +19,6 @@ import { ApiRepository } from './api/api1';
|
||||
import { IRemoteSourcePublisherRegistry } from './remotePublisher';
|
||||
import { IPostCommitCommandsProviderRegistry } from './postCommitCommands';
|
||||
import { IBranchProtectionProviderRegistry } from './branchProtection';
|
||||
import { ObservableSet } from './observable';
|
||||
|
||||
class RepositoryPick implements QuickPickItem {
|
||||
@memoize get label(): string {
|
||||
@@ -35,50 +34,6 @@ class RepositoryPick implements QuickPickItem {
|
||||
constructor(public readonly repository: Repository, public readonly index: number) { }
|
||||
}
|
||||
|
||||
abstract class RepositoryMap<T = void> extends Map<string, T> {
|
||||
constructor() {
|
||||
super();
|
||||
this.updateContextKey();
|
||||
}
|
||||
|
||||
override set(key: string, value: T): this {
|
||||
const result = super.set(key, value);
|
||||
this.updateContextKey();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
override delete(key: string): boolean {
|
||||
const result = super.delete(key);
|
||||
this.updateContextKey();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
abstract updateContextKey(): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* Key - normalized path used in user interface
|
||||
* Value - path extracted from the output of the `git status` command
|
||||
* used when calling `git config --global --add safe.directory`
|
||||
*/
|
||||
class UnsafeRepositoryMap extends RepositoryMap<string> {
|
||||
updateContextKey(): void {
|
||||
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this.size);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Key - normalized path used in user interface
|
||||
* Value - value indicating whether the repository should be opened
|
||||
*/
|
||||
class ParentRepositoryMap extends RepositoryMap {
|
||||
updateContextKey(): void {
|
||||
commands.executeCommand('setContext', 'git.parentRepositoryCount', this.size);
|
||||
}
|
||||
}
|
||||
|
||||
export interface ModelChangeEvent {
|
||||
repository: Repository;
|
||||
uri: Uri;
|
||||
@@ -93,6 +48,122 @@ interface OpenRepository extends Disposable {
|
||||
repository: Repository;
|
||||
}
|
||||
|
||||
class ClosedRepositoriesManager {
|
||||
|
||||
private _repositories: Set<string>;
|
||||
get repositories(): string[] {
|
||||
return [...this._repositories.values()];
|
||||
}
|
||||
|
||||
constructor(private readonly workspaceState: Memento) {
|
||||
this._repositories = new Set<string>(workspaceState.get<string[]>('closedRepositories', []));
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
addRepository(repository: string): void {
|
||||
this._repositories.add(repository);
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
deleteRepository(repository: string): boolean {
|
||||
const result = this._repositories.delete(repository);
|
||||
if (result) {
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
isRepositoryClosed(repository: string): boolean {
|
||||
return this._repositories.has(repository);
|
||||
}
|
||||
|
||||
private onDidChangeRepositories(): void {
|
||||
this.workspaceState.update('closedRepositories', [...this._repositories.values()]);
|
||||
commands.executeCommand('setContext', 'git.closedRepositoryCount', this._repositories.size);
|
||||
}
|
||||
}
|
||||
|
||||
class ParentRepositoriesManager {
|
||||
|
||||
/**
|
||||
* Key - normalized path used in user interface
|
||||
* Value - value indicating whether the repository should be opened
|
||||
*/
|
||||
private _repositories = new Set<string>;
|
||||
get repositories(): string[] {
|
||||
return [...this._repositories.values()];
|
||||
}
|
||||
|
||||
constructor(private readonly globalState: Memento) { }
|
||||
|
||||
addRepository(repository: string): void {
|
||||
this._repositories.add(repository);
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
deleteRepository(repository: string): boolean {
|
||||
const result = this._repositories.delete(repository);
|
||||
if (result) {
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
hasRepository(repository: string): boolean {
|
||||
return this._repositories.has(repository);
|
||||
}
|
||||
|
||||
openRepository(repository: string): void {
|
||||
this.globalState.update(`parentRepository:${repository}`, true);
|
||||
this.deleteRepository(repository);
|
||||
}
|
||||
|
||||
private onDidChangeRepositories(): void {
|
||||
commands.executeCommand('setContext', 'git.parentRepositoryCount', this._repositories.size);
|
||||
}
|
||||
}
|
||||
|
||||
class UnsafeRepositoriesManager {
|
||||
|
||||
/**
|
||||
* Key - normalized path used in user interface
|
||||
* Value - path extracted from the output of the `git status` command
|
||||
* used when calling `git config --global --add safe.directory`
|
||||
*/
|
||||
private _repositories = new Map<string, string>();
|
||||
get repositories(): string[] {
|
||||
return [...this._repositories.keys()];
|
||||
}
|
||||
|
||||
addRepository(repository: string, path: string): void {
|
||||
this._repositories.set(repository, path);
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
deleteRepository(repository: string): boolean {
|
||||
const result = this._repositories.delete(repository);
|
||||
if (result) {
|
||||
this.onDidChangeRepositories();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
getRepositoryPath(repository: string): string | undefined {
|
||||
return this._repositories.get(repository);
|
||||
}
|
||||
|
||||
hasRepository(repository: string): boolean {
|
||||
return this._repositories.has(repository);
|
||||
}
|
||||
|
||||
private onDidChangeRepositories(): void {
|
||||
commands.executeCommand('setContext', 'git.unsafeRepositoryCount', this._repositories.size);
|
||||
}
|
||||
}
|
||||
|
||||
export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePublisherRegistry, IPostCommitCommandsProviderRegistry, IPushErrorHandlerRegistry {
|
||||
|
||||
private _onDidOpenRepository = new EventEmitter<Repository>();
|
||||
@@ -160,19 +231,19 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
|
||||
private pushErrorHandlers = new Set<PushErrorHandler>();
|
||||
|
||||
private _unsafeRepositories = new UnsafeRepositoryMap();
|
||||
get unsafeRepositories(): UnsafeRepositoryMap {
|
||||
return this._unsafeRepositories;
|
||||
private _unsafeRepositoriesManager: UnsafeRepositoriesManager;
|
||||
get unsafeRepositories(): string[] {
|
||||
return this._unsafeRepositoriesManager.repositories;
|
||||
}
|
||||
|
||||
private _parentRepositories = new ParentRepositoryMap();
|
||||
get parentRepositories(): ParentRepositoryMap {
|
||||
return this._parentRepositories;
|
||||
private _parentRepositoriesManager: ParentRepositoriesManager;
|
||||
get parentRepositories(): string[] {
|
||||
return this._parentRepositoriesManager.repositories;
|
||||
}
|
||||
|
||||
private _closedRepositories: ObservableSet<string>;
|
||||
private _closedRepositoriesManager: ClosedRepositoriesManager;
|
||||
get closedRepositories(): string[] {
|
||||
return [...this._closedRepositories.values()];
|
||||
return [...this._closedRepositoriesManager.repositories];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -187,10 +258,11 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
|
||||
private disposables: Disposable[] = [];
|
||||
|
||||
constructor(readonly git: Git, private readonly askpass: Askpass, private globalState: Memento, private workspaceState: Memento, private logger: LogOutputChannel, private telemetryReporter: TelemetryReporter) {
|
||||
this._closedRepositories = new ObservableSet<string>(workspaceState.get<string[]>('closedRepositories', []));
|
||||
this._closedRepositories.onDidChange(this.onDidChangeClosedRepositories, this, this.disposables);
|
||||
this.onDidChangeClosedRepositories();
|
||||
constructor(readonly git: Git, private readonly askpass: Askpass, private globalState: Memento, readonly workspaceState: Memento, private logger: LogOutputChannel, private telemetryReporter: TelemetryReporter) {
|
||||
// Repositories managers
|
||||
this._closedRepositoriesManager = new ClosedRepositoriesManager(workspaceState);
|
||||
this._parentRepositoriesManager = new ParentRepositoriesManager(globalState);
|
||||
this._unsafeRepositoriesManager = new UnsafeRepositoriesManager();
|
||||
|
||||
workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables);
|
||||
window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables);
|
||||
@@ -226,11 +298,11 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
await initialScanFn();
|
||||
}
|
||||
|
||||
if (this._parentRepositories.size !== 0 &&
|
||||
if (this.parentRepositories.length !== 0 &&
|
||||
parentRepositoryConfig === 'prompt') {
|
||||
// Parent repositories notification
|
||||
this.showParentRepositoryNotification();
|
||||
} else if (this._unsafeRepositories.size !== 0) {
|
||||
} else if (this.unsafeRepositories.length !== 0) {
|
||||
// Unsafe repositories notification
|
||||
this.showUnsafeRepositoryNotification();
|
||||
}
|
||||
@@ -379,11 +451,6 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
openRepositoriesToDispose.forEach(r => r.dispose());
|
||||
}
|
||||
|
||||
private onDidChangeClosedRepositories(): void {
|
||||
this.workspaceState.update('closedRepositories', [...this._closedRepositories.values()]);
|
||||
commands.executeCommand('setContext', 'git.closedRepositoryCount', this._closedRepositories.size);
|
||||
}
|
||||
|
||||
private async onDidChangeVisibleTextEditors(editors: readonly TextEditor[]): Promise<void> {
|
||||
if (!workspace.isTrusted) {
|
||||
this.logger.trace('[svte] Workspace is not trusted.');
|
||||
@@ -468,13 +535,13 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
if (isRepositoryOutsideWorkspace) {
|
||||
this.logger.trace(`Repository in parent folder: ${repositoryRoot}`);
|
||||
|
||||
if (!this._parentRepositories.has(repositoryRoot)) {
|
||||
if (!this._parentRepositoriesManager.hasRepository(repositoryRoot)) {
|
||||
// Show a notification if the parent repository is opened after the initial scan
|
||||
if (this.state === 'initialized' && parentRepositoryConfig === 'prompt') {
|
||||
this.showParentRepositoryNotification();
|
||||
}
|
||||
|
||||
this._parentRepositories.set(repositoryRoot);
|
||||
this._parentRepositoriesManager.addRepository(repositoryRoot);
|
||||
}
|
||||
|
||||
return;
|
||||
@@ -486,17 +553,17 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
this.logger.trace(`Unsafe repository: ${repositoryRoot}`);
|
||||
|
||||
// Show a notification if the unsafe repository is opened after the initial scan
|
||||
if (this._state === 'initialized' && !this._unsafeRepositories.has(repositoryRoot)) {
|
||||
if (this._state === 'initialized' && !this._unsafeRepositoriesManager.hasRepository(repositoryRoot)) {
|
||||
this.showUnsafeRepositoryNotification();
|
||||
}
|
||||
|
||||
this._unsafeRepositories.set(repositoryRoot, unsafeRepositoryMatch[2]);
|
||||
this._unsafeRepositoriesManager.addRepository(repositoryRoot, unsafeRepositoryMatch[2]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Handle repositories that were closed by the user
|
||||
if (!openIfClosed && this._closedRepositories.has(repositoryRoot)) {
|
||||
if (!openIfClosed && this._closedRepositoriesManager.isRepositoryClosed(repositoryRoot)) {
|
||||
this.logger.trace(`Repository for path ${repositoryRoot} is closed`);
|
||||
return;
|
||||
}
|
||||
@@ -506,7 +573,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
const repository = new Repository(this.git.open(repositoryRoot, dotGit, this.logger), this, this, this, this, this.globalState, this.logger, this.telemetryReporter);
|
||||
|
||||
this.open(repository);
|
||||
this._closedRepositories.delete(repository.root);
|
||||
this._closedRepositoriesManager.deleteRepository(repository.root);
|
||||
|
||||
// Do not await this, we want SCM
|
||||
// to know about the repo asap
|
||||
@@ -518,11 +585,8 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
}
|
||||
|
||||
async openParentRepository(repoPath: string): Promise<void> {
|
||||
// Mark the repository to be opened from the parent folders
|
||||
this.globalState.update(`parentRepository:${repoPath}`, true);
|
||||
|
||||
await this.openRepository(repoPath);
|
||||
this.parentRepositories.delete(repoPath);
|
||||
this._parentRepositoriesManager.openRepository(repoPath);
|
||||
}
|
||||
|
||||
private async getRepositoryRoot(repoPath: string): Promise<{ repositoryRoot: string; unsafeRepositoryMatch: RegExpMatchArray | null }> {
|
||||
@@ -658,7 +722,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
}
|
||||
|
||||
this.logger.info(`Close repository: ${repository.root}`);
|
||||
this._closedRepositories.add(openRepository.repository.root.toString());
|
||||
this._closedRepositoriesManager.addRepository(openRepository.repository.root);
|
||||
|
||||
openRepository.dispose();
|
||||
}
|
||||
@@ -845,6 +909,14 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
return [...this.pushErrorHandlers];
|
||||
}
|
||||
|
||||
getUnsafeRepositoryPath(repository: string): string | undefined {
|
||||
return this._unsafeRepositoriesManager.getRepositoryPath(repository);
|
||||
}
|
||||
|
||||
deleteUnsafeRepository(repository: string): boolean {
|
||||
return this._unsafeRepositoriesManager.deleteRepository(repository);
|
||||
}
|
||||
|
||||
private async isRepositoryOutsideWorkspace(repositoryPath: string): Promise<boolean> {
|
||||
const workspaceFolders = (workspace.workspaceFolders || [])
|
||||
.filter(folder => folder.uri.scheme === 'file');
|
||||
@@ -878,7 +950,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
}
|
||||
|
||||
private async showParentRepositoryNotification(): Promise<void> {
|
||||
const message = this.parentRepositories.size === 1 ?
|
||||
const message = this.parentRepositories.length === 1 ?
|
||||
l10n.t('A git repository was found in the parent folders of the workspace or the open file(s). Would you like to open the repository?') :
|
||||
l10n.t('Git repositories were found in the parent folders of the workspace or the open file(s). Would you like to open the repositories?');
|
||||
|
||||
@@ -896,7 +968,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
await config.update('openRepositoryInParentFolders', choice === always ? 'always' : 'never', true);
|
||||
|
||||
if (choice === always) {
|
||||
for (const parentRepository of [...this.parentRepositories.keys()]) {
|
||||
for (const parentRepository of this.parentRepositories) {
|
||||
await this.openParentRepository(parentRepository);
|
||||
}
|
||||
}
|
||||
@@ -911,7 +983,7 @@ export class Model implements IBranchProtectionProviderRegistry, IRemoteSourcePu
|
||||
return;
|
||||
}
|
||||
|
||||
const message = this._unsafeRepositories.size === 1 ?
|
||||
const message = this.unsafeRepositories.length === 1 ?
|
||||
l10n.t('The git repository in the current folder is potentially unsafe as the folder is owned by someone other than the current user.') :
|
||||
l10n.t('The git repositories in the current folder are potentially unsafe as the folders are owned by someone other than the current user.');
|
||||
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { EventEmitter } from 'vscode';
|
||||
|
||||
export class ObservableSet<T> implements Set<T> {
|
||||
|
||||
readonly [Symbol.toStringTag]: string = 'ObservableSet';
|
||||
|
||||
private _set: Set<T>;
|
||||
private _onDidChange = new EventEmitter<void>();
|
||||
readonly onDidChange = this._onDidChange.event;
|
||||
|
||||
constructor(values?: readonly T[] | null) {
|
||||
this._set = new Set(values);
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._set.size;
|
||||
}
|
||||
|
||||
add(value: T): this {
|
||||
this._set.add(value);
|
||||
this._onDidChange.fire();
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
clear(): void {
|
||||
if (this._set.size > 0) {
|
||||
this._set.clear();
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
}
|
||||
|
||||
delete(value: T): boolean {
|
||||
const result = this._set.delete(value);
|
||||
if (result) {
|
||||
this._onDidChange.fire();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
forEach(callbackfn: (value: T, value2: T, set: Set<T>) => void, thisArg?: any): void {
|
||||
this._set.forEach((_value, key) => callbackfn.call(thisArg, key, key, this));
|
||||
}
|
||||
|
||||
has(value: T): boolean {
|
||||
return this._set.has(value);
|
||||
}
|
||||
|
||||
entries(): IterableIterator<[T, T]> {
|
||||
return this._set.entries();
|
||||
}
|
||||
|
||||
keys(): IterableIterator<T> {
|
||||
return this._set.keys();
|
||||
}
|
||||
|
||||
values(): IterableIterator<T> {
|
||||
return this._set.keys();
|
||||
}
|
||||
|
||||
[Symbol.iterator](): IterableIterator<T> {
|
||||
return this.keys();
|
||||
}
|
||||
}
|
||||
@@ -5,47 +5,14 @@
|
||||
//@ts-check
|
||||
|
||||
const path = require('path');
|
||||
const fse = require('fs-extra');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'notebook-src');
|
||||
const outDir = path.join(outputRoot, 'notebook-out');
|
||||
const outDir = path.join(__dirname, 'notebook-out');
|
||||
|
||||
async function build() {
|
||||
await esbuild.build({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'cellAttachmentRenderer.ts'),
|
||||
],
|
||||
bundle: true,
|
||||
minify: false,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, async () => {
|
||||
try {
|
||||
await build();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'cellAttachmentRenderer.ts'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
|
||||
@@ -8,12 +8,12 @@ const fs = require('fs');
|
||||
const webpack = require('webpack');
|
||||
const fancyLog = require('fancy-log');
|
||||
const ansiColors = require('ansi-colors');
|
||||
const { Mangler } = require('../build/lib/mangleTypeScript');
|
||||
const { Mangler } = require('../build/lib/mangle/index');
|
||||
|
||||
/**
|
||||
* Map of project paths to mangled file contents
|
||||
*
|
||||
* @type {Map<string, Map<string, { out: string; sourceMap?: string }>>}
|
||||
* @type {Map<string, Promise<Map<string, { out: string; sourceMap?: string }>>>}
|
||||
*/
|
||||
const mangleMap = new Map();
|
||||
|
||||
@@ -25,7 +25,7 @@ function getMangledFileContents(projectPath) {
|
||||
if (!entry) {
|
||||
const log = (...data) => fancyLog(ansiColors.blue('[mangler]'), ...data);
|
||||
log(`Mangling ${projectPath}`);
|
||||
const ts2tsMangler = new Mangler(projectPath, log);
|
||||
const ts2tsMangler = new Mangler(projectPath, log, { mangleExports: true, manglePrivateFields: true });
|
||||
entry = ts2tsMangler.computeNewFileContents();
|
||||
mangleMap.set(projectPath, entry);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ module.exports = async function (source, sourceMap, meta) {
|
||||
|
||||
const callback = this.async();
|
||||
|
||||
const fileContentsMap = getMangledFileContents(options.configFile);
|
||||
const fileContentsMap = await getMangledFileContents(options.configFile);
|
||||
|
||||
const newContents = fileContentsMap.get(this.resourcePath);
|
||||
callback(null, newContents?.out ?? source, sourceMap, meta);
|
||||
|
||||
@@ -4,42 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'notebook');
|
||||
const outDir = path.join(outputRoot, 'notebook-out');
|
||||
const outDir = path.join(__dirname, 'notebook-out');
|
||||
|
||||
function build() {
|
||||
return esbuild.build({
|
||||
entryPoints: [
|
||||
path.join(__dirname, 'notebook', 'index.ts'),
|
||||
],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, () => {
|
||||
return build();
|
||||
});
|
||||
}
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
|
||||
@@ -4,42 +4,15 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'preview-src');
|
||||
const outDir = path.join(outputRoot, 'media');
|
||||
const outDir = path.join(__dirname, 'media');
|
||||
|
||||
function build() {
|
||||
return esbuild.build({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
path.join(srcDir, 'pre'),
|
||||
],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
format: 'iife',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
}
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, () => {
|
||||
return build();
|
||||
});
|
||||
}
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
path.join(srcDir, 'pre'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
|
||||
@@ -6,35 +6,13 @@
|
||||
|
||||
const path = require('path');
|
||||
const fse = require('fs-extra');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'notebook');
|
||||
const outDir = path.join(outputRoot, 'notebook-out');
|
||||
|
||||
async function build() {
|
||||
await esbuild.build({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'katex.ts'),
|
||||
],
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
const outDir = path.join(__dirname, 'notebook-out');
|
||||
|
||||
function postBuild(outDir) {
|
||||
fse.copySync(
|
||||
path.join(__dirname, 'node_modules', 'katex', 'dist', 'katex.min.css'),
|
||||
path.join(outDir, 'katex.min.css'));
|
||||
@@ -51,16 +29,10 @@ async function build() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, async () => {
|
||||
try {
|
||||
await build();
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'katex.ts'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv, postBuild);
|
||||
|
||||
@@ -4,41 +4,14 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'src');
|
||||
const outDir = path.join(outputRoot, 'renderer-out');
|
||||
const outDir = path.join(__dirname, 'renderer-out');
|
||||
|
||||
function build() {
|
||||
return esbuild.build({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
],
|
||||
bundle: true,
|
||||
minify: false,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
}
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, () => {
|
||||
return build();
|
||||
});
|
||||
}
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: [
|
||||
path.join(srcDir, 'index.ts'),
|
||||
],
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
}, process.argv);
|
||||
|
||||
@@ -140,7 +140,7 @@ export async function getPackageManager(extensionContext: ExtensionContext, fold
|
||||
window.showInformationMessage(multiplePMWarning, learnMore, neverShowAgain).then(result => {
|
||||
switch (result) {
|
||||
case neverShowAgain: extensionContext.globalState.update(neverShowWarning, true); break;
|
||||
case learnMore: env.openExternal(Uri.parse('https://nodejs.dev/learn/the-package-lock-json-file'));
|
||||
case learnMore: env.openExternal(Uri.parse('https://docs.npmjs.com/cli/v9/configuring-npm/package-lock-json'));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4,45 +4,20 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
// @ts-check
|
||||
const path = require('path');
|
||||
const esbuild = require('esbuild');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
|
||||
const isWatch = args.indexOf('--watch') >= 0;
|
||||
|
||||
let outputRoot = __dirname;
|
||||
const outputRootIndex = args.indexOf('--outputRoot');
|
||||
if (outputRootIndex >= 0) {
|
||||
outputRoot = args[outputRootIndex + 1];
|
||||
}
|
||||
|
||||
const srcDir = path.join(__dirname, 'preview-src');
|
||||
const outDir = path.join(outputRoot, 'media');
|
||||
const outDir = path.join(__dirname, 'media');
|
||||
|
||||
async function build() {
|
||||
await esbuild.build({
|
||||
entryPoints: {
|
||||
'index': path.join(srcDir, 'index.ts'),
|
||||
'codicon': path.join(__dirname, 'node_modules', 'vscode-codicons', 'dist', 'codicon.css'),
|
||||
},
|
||||
require('../esbuild-webview-common').run({
|
||||
entryPoints: {
|
||||
'index': path.join(srcDir, 'index.ts'),
|
||||
'codicon': path.join(__dirname, 'node_modules', 'vscode-codicons', 'dist', 'codicon.css'),
|
||||
},
|
||||
srcDir,
|
||||
outdir: outDir,
|
||||
additionalOptions: {
|
||||
loader: {
|
||||
'.ttf': 'dataurl',
|
||||
},
|
||||
bundle: true,
|
||||
minify: true,
|
||||
sourcemap: false,
|
||||
format: 'esm',
|
||||
outdir: outDir,
|
||||
platform: 'browser',
|
||||
target: ['es2020'],
|
||||
});
|
||||
}
|
||||
|
||||
build().catch(() => process.exit(1));
|
||||
|
||||
if (isWatch) {
|
||||
const watcher = require('@parcel/watcher');
|
||||
watcher.subscribe(srcDir, () => {
|
||||
return build();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}, process.argv);
|
||||
|
||||
@@ -165,7 +165,7 @@ export class SimpleBrowserView extends Disposable {
|
||||
</header>
|
||||
<div class="content">
|
||||
<div class="iframe-focused-alert">${vscode.l10n.t("Focus Lock")}</div>
|
||||
<iframe sandbox="allow-scripts allow-forms allow-same-origin"></iframe>
|
||||
<iframe sandbox="allow-scripts allow-forms allow-same-origin allow-downloads"></iframe>
|
||||
</div>
|
||||
|
||||
<script src="${mainJs}" nonce="${nonce}"></script>
|
||||
|
||||
@@ -58,7 +58,8 @@ class MyCompletionItem extends vscode.CompletionItem {
|
||||
public readonly metadata: any | undefined,
|
||||
client: ITypeScriptServiceClient,
|
||||
) {
|
||||
super(tsEntry.name, MyCompletionItem.convertKind(tsEntry.kind));
|
||||
const label = tsEntry.name || (tsEntry.insertText ?? '');
|
||||
super(label, MyCompletionItem.convertKind(tsEntry.kind));
|
||||
|
||||
if (tsEntry.source && tsEntry.hasAction && client.apiVersion.lt(API.v490)) {
|
||||
// De-prioritze auto-imports
|
||||
@@ -72,18 +73,18 @@ class MyCompletionItem extends vscode.CompletionItem {
|
||||
// Render "fancy" when source is a workspace path
|
||||
const qualifierCandidate = vscode.workspace.asRelativePath(tsEntry.source);
|
||||
if (qualifierCandidate !== tsEntry.source) {
|
||||
this.label = { label: tsEntry.name, description: qualifierCandidate };
|
||||
this.label = { label, description: qualifierCandidate };
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const { sourceDisplay, isSnippet } = tsEntry;
|
||||
if (sourceDisplay) {
|
||||
this.label = { label: tsEntry.name, description: Previewer.asPlainTextWithLinks(sourceDisplay, client) };
|
||||
this.label = { label, description: Previewer.asPlainTextWithLinks(sourceDisplay, client) };
|
||||
}
|
||||
|
||||
if (tsEntry.labelDetails) {
|
||||
this.label = { label: tsEntry.name, ...tsEntry.labelDetails };
|
||||
this.label = { label, ...tsEntry.labelDetails };
|
||||
}
|
||||
|
||||
this.preselect = tsEntry.isRecommended;
|
||||
|
||||
+11
-11
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.80.0",
|
||||
"distro": "c523cf770e3f05498d5d51a3d7d1dd2d04375276",
|
||||
"distro": "a44605dbeeed7ad5c41513260004329c4f502793",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
@@ -75,6 +75,8 @@
|
||||
"@vscode/sudo-prompt": "9.3.1",
|
||||
"@vscode/vscode-languagedetection": "1.0.21",
|
||||
"@vscode/windows-mutex": "^0.4.4",
|
||||
"@vscode/windows-process-tree": "^0.5.0",
|
||||
"@vscode/windows-registry": "^1.1.0",
|
||||
"graceful-fs": "4.2.8",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.3",
|
||||
@@ -84,20 +86,20 @@
|
||||
"native-is-elevated": "0.6.0",
|
||||
"native-keymap": "^3.3.2",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "0.11.0-beta32",
|
||||
"node-pty": "1.0",
|
||||
"tas-client-umd": "0.1.8",
|
||||
"v8-inspect-profiler": "^0.1.0",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.2.0",
|
||||
"xterm-addon-canvas": "0.4.0",
|
||||
"xterm-addon-image": "0.4.0",
|
||||
"xterm-addon-search": "0.12.0",
|
||||
"xterm-addon-serialize": "0.10.0",
|
||||
"xterm": "5.3.0-beta.1",
|
||||
"xterm-addon-canvas": "0.5.0-beta.1",
|
||||
"xterm-addon-image": "0.4.1",
|
||||
"xterm-addon-search": "0.13.0-beta.1",
|
||||
"xterm-addon-serialize": "0.11.0-beta.1",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.15.0",
|
||||
"xterm-headless": "5.2.0",
|
||||
"xterm-addon-webgl": "0.16.0-beta.1",
|
||||
"xterm-headless": "5.3.0-beta.1",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
@@ -226,8 +228,6 @@
|
||||
"url": "https://github.com/microsoft/vscode/issues"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@vscode/windows-process-tree": "0.4.2",
|
||||
"@vscode/windows-registry": "1.0.10",
|
||||
"windows-foreground-love": "0.5.0"
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -36,6 +36,7 @@
|
||||
{
|
||||
"name": "ms-vscode.js-debug-companion",
|
||||
"version": "1.0.18",
|
||||
"sha256": "b49ee134f452c88fe3de09ae62b7f77aa66d1d6dcd794c48e065bdc2c74d4a30",
|
||||
"repo": "https://github.com/microsoft/vscode-js-debug-companion",
|
||||
"metadata": {
|
||||
"id": "99cb0b7f-7354-4278-b8da-6cc79972169d",
|
||||
@@ -51,6 +52,7 @@
|
||||
{
|
||||
"name": "ms-vscode.js-debug",
|
||||
"version": "1.78.0",
|
||||
"sha256": "9fbf0c15394fb436a4079b5f704d2718d305828be178b1219db85a9287e24870",
|
||||
"repo": "https://github.com/microsoft/vscode-js-debug",
|
||||
"metadata": {
|
||||
"id": "25629058-ddac-4e17-abba-74678e126c5d",
|
||||
@@ -66,6 +68,7 @@
|
||||
{
|
||||
"name": "ms-vscode.vscode-js-profile-table",
|
||||
"version": "1.0.3",
|
||||
"sha256": "b9dab017506d9e6a469a0f82b392e4cb1d7a25a4843f1db8ba396cbee209cfc5",
|
||||
"repo": "https://github.com/microsoft/vscode-js-profile-visualizer",
|
||||
"metadata": {
|
||||
"id": "7e52b41b-71ad-457b-ab7e-0620f1fc4feb",
|
||||
@@ -78,5 +81,9 @@
|
||||
"publisherDisplayName": "Microsoft"
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"nodejs": {
|
||||
"repository": "https://nodejs.org",
|
||||
"version": "16.17.1"
|
||||
}
|
||||
}
|
||||
|
||||
+10
-12
@@ -11,6 +11,8 @@
|
||||
"@vscode/ripgrep": "^1.15.4",
|
||||
"@vscode/spdlog": "^0.13.10",
|
||||
"@vscode/vscode-languagedetection": "1.0.21",
|
||||
"@vscode/windows-process-tree": "^0.5.0",
|
||||
"@vscode/windows-registry": "^1.1.0",
|
||||
"cookie": "^0.4.0",
|
||||
"graceful-fs": "4.2.8",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
@@ -19,24 +21,20 @@
|
||||
"keytar": "7.9.0",
|
||||
"minimist": "^1.2.6",
|
||||
"native-watchdog": "^1.4.1",
|
||||
"node-pty": "0.11.0-beta32",
|
||||
"node-pty": "1.0",
|
||||
"tas-client-umd": "0.1.8",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-regexpp": "^3.1.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.2.0",
|
||||
"xterm-addon-canvas": "0.4.0",
|
||||
"xterm-addon-image": "0.4.0",
|
||||
"xterm-addon-search": "0.12.0",
|
||||
"xterm-addon-serialize": "0.10.0",
|
||||
"xterm": "5.3.0-beta.1",
|
||||
"xterm-addon-canvas": "0.5.0-beta.1",
|
||||
"xterm-addon-image": "0.4.1",
|
||||
"xterm-addon-search": "0.13.0-beta.1",
|
||||
"xterm-addon-serialize": "0.11.0-beta.1",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.15.0",
|
||||
"xterm-headless": "5.2.0",
|
||||
"xterm-addon-webgl": "0.16.0-beta.1",
|
||||
"xterm-headless": "5.3.0-beta.1",
|
||||
"yauzl": "^2.9.2",
|
||||
"yazl": "^2.4.3"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@vscode/windows-process-tree": "0.4.2",
|
||||
"@vscode/windows-registry": "1.0.10"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,11 +11,11 @@
|
||||
"tas-client-umd": "0.1.8",
|
||||
"vscode-oniguruma": "1.7.0",
|
||||
"vscode-textmate": "9.0.0",
|
||||
"xterm": "5.2.0",
|
||||
"xterm-addon-canvas": "0.4.0",
|
||||
"xterm-addon-image": "0.4.0",
|
||||
"xterm-addon-search": "0.12.0",
|
||||
"xterm": "5.3.0-beta.1",
|
||||
"xterm-addon-canvas": "0.5.0-beta.1",
|
||||
"xterm-addon-image": "0.4.1",
|
||||
"xterm-addon-search": "0.13.0-beta.1",
|
||||
"xterm-addon-unicode11": "0.5.0",
|
||||
"xterm-addon-webgl": "0.15.0"
|
||||
"xterm-addon-webgl": "0.16.0-beta.1"
|
||||
}
|
||||
}
|
||||
|
||||
+20
-20
@@ -68,32 +68,32 @@ vscode-textmate@9.0.0:
|
||||
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-9.0.0.tgz#313c6c8792b0507aef35aeb81b6b370b37c44d6c"
|
||||
integrity sha512-Cl65diFGxz7gpwbav10HqiY/eVYTO1sjQpmRmV991Bj7wAoOAjGQ97PpQcXorDE2Uc4hnGWLY17xme+5t6MlSg==
|
||||
|
||||
xterm-addon-canvas@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.4.0.tgz#a6ee6a56deb0c495fcef29afe6d94b7119a0f334"
|
||||
integrity sha512-iTC8CdjX9+hGX7jiEuiDMXzHsY/FKJdVnbjep5xjRXNu7RKOk15xuecIkJ7HZORqMVPpr4DGS3jyd9XUoBuxqw==
|
||||
xterm-addon-canvas@0.5.0-beta.1:
|
||||
version "0.5.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.1.tgz#b5ae185741423715460a66029c944b4dededfab0"
|
||||
integrity sha512-A7yjIpyTcOh8ckPJw1YFDvwbTbQ+grM+kTtutOvu5LjLSV9EoCHX17kVoiT2V29ywF7KJMeLYwfBwyFE3uA3QQ==
|
||||
|
||||
xterm-addon-image@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.0.tgz#36e98fa892db11755a5f6e9654f924e876e29bf8"
|
||||
integrity sha512-3wumCJo4WTzxvecSMxJ7XtpVQeFe4gE2cdHCyUdo7zagVkS18YXJacGx6DjlAIccdJn6/LhGuD99xOSSvYx9Gw==
|
||||
xterm-addon-image@0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.1.tgz#ec8f750af48005ad641c1128fa1f551ac198472a"
|
||||
integrity sha512-iJpYyvtbHg4oXSv+D6J73ZfCjnboZpbZ567MLplXDBlYSUknv3kvPTfVMPJATV7Zsx7+bDgyXboCh9vsDf/m/w==
|
||||
|
||||
xterm-addon-search@0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.12.0.tgz#2ef8f56aecf699a3989223a1260f1e079d7c74e2"
|
||||
integrity sha512-hXAuO7Ts2+Jf9K8mZrUx8IFd7c/Flgks/jyqA1L4reymyfmXtcsd+WDLel8R9Tgy2CLyKABVBP09/Ua/FmXcvg==
|
||||
xterm-addon-search@0.13.0-beta.1:
|
||||
version "0.13.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.1.tgz#9fb6ede402d4c369d59d5d6faefe54a05b125bcf"
|
||||
integrity sha512-rdOIhwkfRASqTriUO8QP9UY0p6BosLMv1NXTZqhgq3/5xAXx4VZg6mlQjTRGnUz/GJIN1jU9e/Vp20SpocP/Hw==
|
||||
|
||||
xterm-addon-unicode11@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7"
|
||||
integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg==
|
||||
|
||||
xterm-addon-webgl@0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.15.0.tgz#c10f93ca619524f5a470eaac44258bab0ae8e3c7"
|
||||
integrity sha512-ZLcqogMFHr4g/YRhcCh3xE8tTklnyut/M+O/XhVsFBRB/YCvYhPdLQ5/AQk54V0wjWAQpa8CF3W8DVR9OqyMCg==
|
||||
xterm-addon-webgl@0.16.0-beta.1:
|
||||
version "0.16.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.1.tgz#e2b41c6b5f838724a5cb3cfa4231e2d1b8f3f130"
|
||||
integrity sha512-iJK+Uk+23Mh84BNa/44JqAdPESdNKN0ONfw6UztmDk2HTvsy47sU+d/lgF2kOcuI3ew2tRzK9YlupOUhVPwe9g==
|
||||
|
||||
xterm@5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.2.0.tgz#7e716bbe448ecef0ea387586c59fbc51a08f9125"
|
||||
integrity sha512-C1NXTZYfXPTXzF7uw7Ao6/IFGrtAkHv4e/PCQRpgYHyMobvaRs3nJNGK32hX/skdMUQJ6yhSnyzfmWCQwG9qvg==
|
||||
xterm@5.3.0-beta.1:
|
||||
version "5.3.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.1.tgz#68e76f2818965592c60bb269360f1fc37219f4ae"
|
||||
integrity sha512-2v/Qmk1A0wO5oouRWUWZ3wxqtfFjxsQbZ1sWxPGJTQvoTSdkORLG44gxrU+Sk2jB5Ojz+3Kg42bnfFghsXVzlw==
|
||||
|
||||
+40
-40
@@ -101,17 +101,17 @@
|
||||
dependencies:
|
||||
node-addon-api "^3.0.2"
|
||||
|
||||
"@vscode/windows-process-tree@0.4.2":
|
||||
version "0.4.2"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.4.2.tgz#54d010fdeb06dfe3a9c6d58fcb3ed9acfc962f33"
|
||||
integrity sha512-b20865s1HG1VtGt887KrB1blwFS6p4L1Fl1o/WplO9j7sGBle8sLqkNnGXbCaRNgdIgfXtitmzG366FVynJZdQ==
|
||||
"@vscode/windows-process-tree@^0.5.0":
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/windows-process-tree/-/windows-process-tree-0.5.0.tgz#b8205b862c75a1e0ad8b7bf4350dc85036ee3a2c"
|
||||
integrity sha512-y8Oliel/rBSYh9f1T4F0zQjJNPeJRgYRhEKZsjas7JXKLf46FpE3Ux8e9+7HelUD8dXFH7C7N6895nU0WhrMlg==
|
||||
dependencies:
|
||||
nan "^2.17.0"
|
||||
|
||||
"@vscode/windows-registry@1.0.10":
|
||||
version "1.0.10"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.0.10.tgz#17e4e2f8fdd41990206d1bab2daf99c803206247"
|
||||
integrity sha512-n2rLdTgv95fQUpDxZqgAURg9neQGymtOKkLW4eYP2SODmaxoL2WzgrxEz1kW0w5TI+J4tsPeuZylpRfrDJKQWw==
|
||||
"@vscode/windows-registry@^1.1.0":
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@vscode/windows-registry/-/windows-registry-1.1.0.tgz#03dace7c29c46f658588b9885b9580e453ad21f9"
|
||||
integrity sha512-5AZzuWJpGscyiMOed0IuyEwt6iKmV5Us7zuwCDCFYMIq7tsvooO9BUiciywsvuthGz6UG4LSpeDeCxvgMVhnIw==
|
||||
|
||||
agent-base@4:
|
||||
version "4.2.0"
|
||||
@@ -537,10 +537,10 @@ node-gyp-build@^4.3.0:
|
||||
resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3"
|
||||
integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q==
|
||||
|
||||
node-pty@0.11.0-beta32:
|
||||
version "0.11.0-beta32"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.11.0-beta32.tgz#49c0f174f600ac3f54a21df2a41b6f78256ff6ce"
|
||||
integrity sha512-xtzB4/jYH64ksdVatYQnaU3TtCtSaDiiZPsZITmLHnywFSpI2bgfyj/bu6ofOXbe8PTtziL8bDn1U3xkRmx3mg==
|
||||
node-pty@1.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-1.0.0.tgz#7daafc0aca1c4ca3de15c61330373af4af5861fd"
|
||||
integrity sha512-wtBMWWS7dFZm/VgqElrTvtfMq4GzJ6+edFI0Y0zyzygUSZMgZdraDUMUhCIvkjhJjme15qWmbyJbtAx4ot4uZA==
|
||||
dependencies:
|
||||
nan "^2.17.0"
|
||||
|
||||
@@ -836,45 +836,45 @@ wrappy@1:
|
||||
resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
|
||||
integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
|
||||
|
||||
xterm-addon-canvas@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.4.0.tgz#a6ee6a56deb0c495fcef29afe6d94b7119a0f334"
|
||||
integrity sha512-iTC8CdjX9+hGX7jiEuiDMXzHsY/FKJdVnbjep5xjRXNu7RKOk15xuecIkJ7HZORqMVPpr4DGS3jyd9XUoBuxqw==
|
||||
xterm-addon-canvas@0.5.0-beta.1:
|
||||
version "0.5.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-canvas/-/xterm-addon-canvas-0.5.0-beta.1.tgz#b5ae185741423715460a66029c944b4dededfab0"
|
||||
integrity sha512-A7yjIpyTcOh8ckPJw1YFDvwbTbQ+grM+kTtutOvu5LjLSV9EoCHX17kVoiT2V29ywF7KJMeLYwfBwyFE3uA3QQ==
|
||||
|
||||
xterm-addon-image@0.4.0:
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.0.tgz#36e98fa892db11755a5f6e9654f924e876e29bf8"
|
||||
integrity sha512-3wumCJo4WTzxvecSMxJ7XtpVQeFe4gE2cdHCyUdo7zagVkS18YXJacGx6DjlAIccdJn6/LhGuD99xOSSvYx9Gw==
|
||||
xterm-addon-image@0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-image/-/xterm-addon-image-0.4.1.tgz#ec8f750af48005ad641c1128fa1f551ac198472a"
|
||||
integrity sha512-iJpYyvtbHg4oXSv+D6J73ZfCjnboZpbZ567MLplXDBlYSUknv3kvPTfVMPJATV7Zsx7+bDgyXboCh9vsDf/m/w==
|
||||
|
||||
xterm-addon-search@0.12.0:
|
||||
version "0.12.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.12.0.tgz#2ef8f56aecf699a3989223a1260f1e079d7c74e2"
|
||||
integrity sha512-hXAuO7Ts2+Jf9K8mZrUx8IFd7c/Flgks/jyqA1L4reymyfmXtcsd+WDLel8R9Tgy2CLyKABVBP09/Ua/FmXcvg==
|
||||
xterm-addon-search@0.13.0-beta.1:
|
||||
version "0.13.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.13.0-beta.1.tgz#9fb6ede402d4c369d59d5d6faefe54a05b125bcf"
|
||||
integrity sha512-rdOIhwkfRASqTriUO8QP9UY0p6BosLMv1NXTZqhgq3/5xAXx4VZg6mlQjTRGnUz/GJIN1jU9e/Vp20SpocP/Hw==
|
||||
|
||||
xterm-addon-serialize@0.10.0:
|
||||
version "0.10.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.10.0.tgz#c16a8cb456dcbd2f008fa83d15ce1d4721892e01"
|
||||
integrity sha512-Syp9eSBypn70iAczcJ+kAi0foQIepAvFS6x53JwI4XylTBHn87Ep9fovslhwmUV3rwH2yMnpdDjXH5W/whx2lA==
|
||||
xterm-addon-serialize@0.11.0-beta.1:
|
||||
version "0.11.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-serialize/-/xterm-addon-serialize-0.11.0-beta.1.tgz#a4bc1ef5d8b8db0180c07f071ce543536d806db1"
|
||||
integrity sha512-2I9Dq49nXUc6ymznwJp8SUsDq5owUdYviUy11HzLh35baDjzbG31CCu5Gs8KSlfUxpNRr3BxaV5/hx7MRPu7Qg==
|
||||
|
||||
xterm-addon-unicode11@0.5.0:
|
||||
version "0.5.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-unicode11/-/xterm-addon-unicode11-0.5.0.tgz#41c0d96acc1e3bb6c6596eee64e163b6bca74be7"
|
||||
integrity sha512-Jm4/g4QiTxiKiTbYICQgC791ubhIZyoIwxAIgOW8z8HWFNY+lwk+dwaKEaEeGBfM48Vk8fklsUW9u/PlenYEBg==
|
||||
|
||||
xterm-addon-webgl@0.15.0:
|
||||
version "0.15.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.15.0.tgz#c10f93ca619524f5a470eaac44258bab0ae8e3c7"
|
||||
integrity sha512-ZLcqogMFHr4g/YRhcCh3xE8tTklnyut/M+O/XhVsFBRB/YCvYhPdLQ5/AQk54V0wjWAQpa8CF3W8DVR9OqyMCg==
|
||||
xterm-addon-webgl@0.16.0-beta.1:
|
||||
version "0.16.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-addon-webgl/-/xterm-addon-webgl-0.16.0-beta.1.tgz#e2b41c6b5f838724a5cb3cfa4231e2d1b8f3f130"
|
||||
integrity sha512-iJK+Uk+23Mh84BNa/44JqAdPESdNKN0ONfw6UztmDk2HTvsy47sU+d/lgF2kOcuI3ew2tRzK9YlupOUhVPwe9g==
|
||||
|
||||
xterm-headless@5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.2.0.tgz#7e75d1b942e319976bf982d1682516db006a5368"
|
||||
integrity sha512-FPrzB7CxyzrjEEGU7dEXVtVFjDx2YIPkx/lOfKPTarJl3BtZfFvuWUAXRD+KIrV5zy1QvAoqmiBOsG+sXC9knQ==
|
||||
xterm-headless@5.3.0-beta.1:
|
||||
version "5.3.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm-headless/-/xterm-headless-5.3.0-beta.1.tgz#8c7db703b9f57496c2f052411721c00909b08e8b"
|
||||
integrity sha512-6rsv6l44hLL9Eg2UrfAbCiZcAucdHuPyIsovl2BEmluo4chwd4LD7VINRlPV/x8ML2HgD9SohFyNs5BQAc07Gg==
|
||||
|
||||
xterm@5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.2.0.tgz#7e716bbe448ecef0ea387586c59fbc51a08f9125"
|
||||
integrity sha512-C1NXTZYfXPTXzF7uw7Ao6/IFGrtAkHv4e/PCQRpgYHyMobvaRs3nJNGK32hX/skdMUQJ6yhSnyzfmWCQwG9qvg==
|
||||
xterm@5.3.0-beta.1:
|
||||
version "5.3.0-beta.1"
|
||||
resolved "https://registry.yarnpkg.com/xterm/-/xterm-5.3.0-beta.1.tgz#68e76f2818965592c60bb269360f1fc37219f4ae"
|
||||
integrity sha512-2v/Qmk1A0wO5oouRWUWZ3wxqtfFjxsQbZ1sWxPGJTQvoTSdkORLG44gxrU+Sk2jB5Ojz+3Kg42bnfFghsXVzlw==
|
||||
|
||||
yallist@^4.0.0:
|
||||
version "4.0.0"
|
||||
|
||||
+13
-5
@@ -27,17 +27,19 @@ const { getUNCHost, addUNCHostToAllowlist } = require('./vs/base/node/unc');
|
||||
const product = require('../product.json');
|
||||
const { app, protocol, crashReporter, Menu } = require('electron');
|
||||
|
||||
// Enable sandbox globally
|
||||
app.enableSandbox();
|
||||
|
||||
// Enable portable support
|
||||
const portable = bootstrapNode.configurePortable(product);
|
||||
|
||||
// Enable ASAR support
|
||||
bootstrap.enableASARSupport();
|
||||
|
||||
// Set userData path before app 'ready' event
|
||||
// Enable sandbox globally unless disabled via `--no-sandbox` argument
|
||||
const args = parseCLIArgs();
|
||||
if (args['sandbox']) {
|
||||
app.enableSandbox();
|
||||
}
|
||||
|
||||
// Set userData path before app 'ready' event
|
||||
const userDataPath = getUserDataPath(args, product.nameShort ?? 'code-oss-dev');
|
||||
if (process.platform === 'win32') {
|
||||
const userDataUNCHost = getUNCHost(userDataPath);
|
||||
@@ -464,7 +466,13 @@ function parseCLIArgs() {
|
||||
'locale',
|
||||
'js-flags',
|
||||
'crash-reporter-directory'
|
||||
]
|
||||
],
|
||||
default: {
|
||||
'sandbox': true
|
||||
},
|
||||
alias: {
|
||||
'no-sandbox': 'sandbox'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
-75
@@ -1,75 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
// Copied from the `@vscode/windows-process-tree` package.
|
||||
// The dependency is an optional dependency that is only used on Windows,
|
||||
// but we need the typings to compile on all platforms.
|
||||
// The `@types/windows-process-tree` package has also been deprecated.
|
||||
declare module '@vscode/windows-process-tree' {
|
||||
export enum ProcessDataFlag { }
|
||||
|
||||
export interface IProcessInfo {
|
||||
pid: number;
|
||||
ppid: number;
|
||||
name: string;
|
||||
|
||||
/**
|
||||
* The working set size of the process, in bytes.
|
||||
*/
|
||||
memory?: number;
|
||||
|
||||
/**
|
||||
* The string returned is at most 512 chars, strings exceeding this length are truncated.
|
||||
*/
|
||||
commandLine?: string;
|
||||
}
|
||||
|
||||
export interface IProcessCpuInfo extends IProcessInfo {
|
||||
cpu?: number;
|
||||
}
|
||||
|
||||
export interface IProcessTreeNode {
|
||||
pid: number;
|
||||
name: string;
|
||||
memory?: number;
|
||||
commandLine?: string;
|
||||
children: IProcessTreeNode[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a tree of processes with the rootPid process as the root.
|
||||
* @param rootPid - The pid of the process that will be the root of the tree.
|
||||
* @param callback - The callback to use with the returned list of processes.
|
||||
* @param flags - The flags for what process data should be included.
|
||||
*/
|
||||
export function getProcessTree(rootPid: number, callback: (tree: IProcessTreeNode | undefined) => void, flags?: ProcessDataFlag): void;
|
||||
|
||||
namespace getProcessTree {
|
||||
function __promisify__(rootPid: number, flags?: ProcessDataFlag): Promise<IProcessTreeNode>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of processes containing the rootPid process and all of its descendants.
|
||||
* @param rootPid - The pid of the process of interest.
|
||||
* @param callback - The callback to use with the returned set of processes.
|
||||
* @param flags - The flags for what process data should be included.
|
||||
*/
|
||||
export function getProcessList(rootPid: number, callback: (processList: IProcessInfo[] | undefined) => void, flags?: ProcessDataFlag): void;
|
||||
|
||||
namespace getProcessList {
|
||||
function __promisify__(rootPid: number, flags?: ProcessDataFlag): Promise<IProcessInfo[]>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of processes annotated with cpu usage information.
|
||||
* @param processList - The list of processes.
|
||||
* @param callback - The callback to use with the returned list of processes.
|
||||
*/
|
||||
export function getProcessCpuUsage(processList: IProcessInfo[], callback: (processListWithCpu: IProcessCpuInfo[]) => void): void;
|
||||
|
||||
namespace getProcessCpuUsage {
|
||||
function __promisify__(processList: IProcessInfo[]): Promise<IProcessCpuInfo[]>;
|
||||
}
|
||||
}
|
||||
Vendored
-9
@@ -1,9 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
declare module '@vscode/windows-registry' {
|
||||
export type HKEY = 'HKEY_CURRENT_USER' | 'HKEY_LOCAL_MACHINE' | 'HKEY_CLASSES_ROOT' | 'HKEY_USERS' | 'HKEY_CURRENT_CONFIG';
|
||||
export function GetStringRegKey(hive: HKEY, path: string, name: string): string | undefined;
|
||||
}
|
||||
@@ -129,11 +129,25 @@ class Trait<T> implements ISpliceable<boolean>, IDisposable {
|
||||
|
||||
const diff = elements.length - deleteCount;
|
||||
const end = start + deleteCount;
|
||||
const sortedIndexes = [
|
||||
...this.sortedIndexes.filter(i => i < start),
|
||||
...elements.map((hasTrait, i) => hasTrait ? i + start : -1).filter(i => i !== -1),
|
||||
...this.sortedIndexes.filter(i => i >= end).map(i => i + diff)
|
||||
];
|
||||
const sortedIndexes: number[] = [];
|
||||
let firstSortedIndex: number | undefined = undefined;
|
||||
let i = 0;
|
||||
|
||||
while (i < this.sortedIndexes.length && this.sortedIndexes[i] < start) {
|
||||
sortedIndexes.push(this.sortedIndexes[i++]);
|
||||
}
|
||||
|
||||
for (let j = 0; j < elements.length; j++) {
|
||||
if (elements[j]) {
|
||||
sortedIndexes.push(j + start);
|
||||
firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1];
|
||||
}
|
||||
}
|
||||
|
||||
while (i < this.sortedIndexes.length && this.sortedIndexes[i] >= end) {
|
||||
sortedIndexes.push(this.sortedIndexes[i++] + diff);
|
||||
firstSortedIndex = firstSortedIndex ?? sortedIndexes[sortedIndexes.length - 1];
|
||||
}
|
||||
|
||||
const length = this.length + diff;
|
||||
|
||||
@@ -226,12 +240,16 @@ class TraitSpliceable<T> implements ISpliceable<T> {
|
||||
|
||||
splice(start: number, deleteCount: number, elements: T[]): void {
|
||||
if (!this.identityProvider) {
|
||||
return this.trait.splice(start, deleteCount, elements.map(() => false));
|
||||
return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));
|
||||
}
|
||||
|
||||
const pastElementsWithTrait = this.trait.get().map(i => this.identityProvider!.getId(this.view.element(i)).toString());
|
||||
const elementsWithTrait = elements.map(e => pastElementsWithTrait.indexOf(this.identityProvider!.getId(e).toString()) > -1);
|
||||
if (pastElementsWithTrait.length === 0) {
|
||||
return this.trait.splice(start, deleteCount, new Array(elements.length).fill(false));
|
||||
}
|
||||
|
||||
const pastElementsWithTraitSet = new Set(pastElementsWithTrait);
|
||||
const elementsWithTrait = elements.map(e => pastElementsWithTraitSet.has(this.identityProvider!.getId(e).toString()));
|
||||
this.trait.splice(start, deleteCount, elementsWithTrait);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ export class ErrorHandler {
|
||||
|
||||
export const errorHandler = new ErrorHandler();
|
||||
|
||||
/** @skipMangle */
|
||||
export function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
|
||||
errorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);
|
||||
}
|
||||
|
||||
@@ -4,11 +4,12 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { BugIndicatingError } from 'vs/base/common/errors';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IReader, IObservable, BaseObservable, IObserver, _setDerived, IChangeContext } from 'vs/base/common/observableImpl/base';
|
||||
import { getLogger } from 'vs/base/common/observableImpl/logging';
|
||||
|
||||
export function derived<T>(debugName: string | (() => string), computeFn: (reader: IReader) => T): IObservable<T> {
|
||||
return new Derived(debugName, computeFn, undefined, undefined);
|
||||
return new Derived(debugName, computeFn, undefined, undefined, undefined);
|
||||
}
|
||||
|
||||
export function derivedHandleChanges<T, TChangeSummary>(
|
||||
@@ -18,7 +19,15 @@ export function derivedHandleChanges<T, TChangeSummary>(
|
||||
handleChange: (context: IChangeContext, changeSummary: TChangeSummary) => boolean;
|
||||
},
|
||||
computeFn: (reader: IReader, changeSummary: TChangeSummary) => T): IObservable<T> {
|
||||
return new Derived(debugName, computeFn, options.createEmptyChangeSummary, options.handleChange);
|
||||
return new Derived(debugName, computeFn, options.createEmptyChangeSummary, options.handleChange, undefined);
|
||||
}
|
||||
|
||||
export function derivedWithStore<T>(name: string, computeFn: (reader: IReader, store: DisposableStore) => T): IObservable<T> {
|
||||
const store = new DisposableStore();
|
||||
return new Derived(name, r => {
|
||||
store.clear();
|
||||
return computeFn(r, store);
|
||||
}, undefined, undefined, () => store.dispose());
|
||||
}
|
||||
|
||||
_setDerived(derived);
|
||||
@@ -62,6 +71,7 @@ export class Derived<T, TChangeSummary = any> extends BaseObservable<T, void> im
|
||||
private readonly computeFn: (reader: IReader, changeSummary: TChangeSummary) => T,
|
||||
private readonly createChangeSummary: (() => TChangeSummary) | undefined,
|
||||
private readonly _handleChange: ((context: IChangeContext, summary: TChangeSummary) => boolean) | undefined,
|
||||
private readonly _handleLastObserverRemoved: (() => void) | undefined = undefined
|
||||
) {
|
||||
super();
|
||||
this.changeSummary = this.createChangeSummary?.();
|
||||
@@ -79,6 +89,8 @@ export class Derived<T, TChangeSummary = any> extends BaseObservable<T, void> im
|
||||
d.removeObserver(this);
|
||||
}
|
||||
this.dependencies.clear();
|
||||
|
||||
this._handleLastObserverRemoved?.();
|
||||
}
|
||||
|
||||
public override get(): T {
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { autorun } from 'vs/base/common/observableImpl/autorun';
|
||||
import { IObservable, BaseObservable, transaction, IReader, ITransaction, ConvenientObservable, IObserver, observableValue, getFunctionName } from 'vs/base/common/observableImpl/base';
|
||||
import { BaseObservable, ConvenientObservable, IObservable, IObserver, IReader, ITransaction, getFunctionName, observableValue, transaction } from 'vs/base/common/observableImpl/base';
|
||||
import { derived } from 'vs/base/common/observableImpl/derived';
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { getLogger } from 'vs/base/common/observableImpl/logging';
|
||||
|
||||
export function constObservable<T>(value: T): IObservable<T> {
|
||||
|
||||
@@ -48,6 +48,8 @@ else {
|
||||
* environments.
|
||||
*
|
||||
* Note: in web, this property is hardcoded to be `/`.
|
||||
*
|
||||
* @skipMangle
|
||||
*/
|
||||
export const cwd = safeProcess.cwd;
|
||||
|
||||
|
||||
+1
-1
@@ -10,5 +10,5 @@
|
||||
* supported in JSON.
|
||||
* @param content the content to strip comments from
|
||||
* @returns the content without comments
|
||||
*/
|
||||
*/
|
||||
export function stripComments(content: string): string;
|
||||
|
||||
@@ -558,6 +558,7 @@ export class SimpleWorkerServer<H extends object> {
|
||||
|
||||
/**
|
||||
* Called on the worker side
|
||||
* @skipMangle
|
||||
*/
|
||||
export function create(postMessage: (msg: Message, transfer?: ArrayBuffer[]) => void): SimpleWorkerServer<any> {
|
||||
return new SimpleWorkerServer(postMessage, null);
|
||||
|
||||
@@ -115,13 +115,13 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
|
||||
const cleanUNCPrefix = (value: string): string => {
|
||||
if (value.indexOf('\\\\?\\') === 0) {
|
||||
return value.substr(4);
|
||||
return value.substring(4);
|
||||
} else if (value.indexOf('\\??\\') === 0) {
|
||||
return value.substr(4);
|
||||
return value.substring(4);
|
||||
} else if (value.indexOf('"\\\\?\\') === 0) {
|
||||
return '"' + value.substr(5);
|
||||
return '"' + value.substring(5);
|
||||
} else if (value.indexOf('"\\??\\') === 0) {
|
||||
return '"' + value.substr(5);
|
||||
return '"' + value.substring(5);
|
||||
} else {
|
||||
return value;
|
||||
}
|
||||
@@ -169,10 +169,7 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
reject(new Error(`Root process ${rootPid} not found`));
|
||||
}
|
||||
});
|
||||
},
|
||||
// Workaround duplicate enum identifiers issue in @vscode/windows-process-tree
|
||||
// Ref https://github.com/microsoft/vscode/pull/179508
|
||||
(windowsProcessTree.ProcessDataFlag as any).CommandLine | (windowsProcessTree.ProcessDataFlag as any).Memory);
|
||||
}, windowsProcessTree.ProcessDataFlag.CommandLine | windowsProcessTree.ProcessDataFlag.Memory);
|
||||
});
|
||||
} else { // OS X & Linux
|
||||
function calculateLinuxCpuUsage() {
|
||||
|
||||
Vendored
+5
@@ -23,3 +23,8 @@ export function addUNCHostToAllowlist(allowedHost: string | string[]): void;
|
||||
* path validation.
|
||||
*/
|
||||
export function disableUNCAccessRestrictions(): void;
|
||||
|
||||
/**
|
||||
* Whether UNC Host allow list in node.js is disabled.
|
||||
*/
|
||||
export function isUNCAccessRestrictionsDisabled(): boolean;
|
||||
|
||||
+10
-1
@@ -117,11 +117,20 @@
|
||||
process.enableUNCAccessChecks = false;
|
||||
}
|
||||
|
||||
function isUNCAccessRestrictionsDisabled() {
|
||||
if (process.platform !== 'win32') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return process.enableUNCAccessChecks === false;
|
||||
}
|
||||
|
||||
return {
|
||||
getUNCHostAllowlist,
|
||||
addUNCHostToAllowlist,
|
||||
getUNCHost,
|
||||
disableUNCAccessRestrictions
|
||||
disableUNCAccessRestrictions,
|
||||
isUNCAccessRestrictionsDisabled
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -382,7 +382,7 @@ class CodeMain {
|
||||
|
||||
// Print --status usage info
|
||||
if (environmentMainService.args.status) {
|
||||
logService.warn(localize('statusWarning', "Warning: The --status argument can only be used if {0} is already running. Please run it again after {0} has started.", productService.nameShort));
|
||||
console.log(localize('statusWarning', "Warning: The --status argument can only be used if {0} is already running. Please run it again after {0} has started.", productService.nameShort));
|
||||
|
||||
throw new ExpectedError('Terminating...');
|
||||
}
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
cellRendererEditorText
|
||||
defaultWorkerFactory
|
||||
diffEditorWidget
|
||||
diffEditorWidget2
|
||||
diffReview
|
||||
domLineBreaksComputer
|
||||
dompurify
|
||||
|
||||
@@ -49,6 +49,7 @@
|
||||
cellRendererEditorText
|
||||
defaultWorkerFactory
|
||||
diffEditorWidget
|
||||
diffEditorWidget2
|
||||
diffReview
|
||||
domLineBreaksComputer
|
||||
dompurify
|
||||
|
||||
@@ -9,6 +9,8 @@ interface ICSSPluginConfig {
|
||||
|
||||
/**
|
||||
* Invoked by the loader at run-time
|
||||
*
|
||||
* @skipMangle
|
||||
*/
|
||||
export function load(name: string, req: AMDLoader.IRelativeRequire, load: AMDLoader.IPluginLoadCallback, config: AMDLoader.IConfigurationOptions): void {
|
||||
config = config || {};
|
||||
|
||||
@@ -297,7 +297,12 @@ export class TextAreaHandler extends ViewPart {
|
||||
};
|
||||
|
||||
const textAreaWrapper = this._register(new TextAreaWrapper(this.textArea.domNode));
|
||||
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, textAreaWrapper, platform.OS, browser));
|
||||
this._textAreaInput = this._register(new TextAreaInput(textAreaInputHost, textAreaWrapper, platform.OS, {
|
||||
isAndroid: browser.isAndroid,
|
||||
isChrome: browser.isChrome,
|
||||
isFirefox: browser.isFirefox,
|
||||
isSafari: browser.isSafari,
|
||||
}));
|
||||
|
||||
this._register(this._textAreaInput.onKeyDown((e: IKeyboardEvent) => {
|
||||
this._viewController.emitKeyDown(e);
|
||||
|
||||
@@ -1095,13 +1095,6 @@ export interface IActiveCodeEditor extends ICodeEditor {
|
||||
getScrolledVisiblePosition(position: IPosition): { top: number; left: number; height: number };
|
||||
}
|
||||
|
||||
/**
|
||||
* Information about a line in the diff editor
|
||||
*/
|
||||
export interface IDiffLineInformation {
|
||||
readonly equivalentLineNumber: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
@@ -1164,6 +1157,8 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
*/
|
||||
getModel(): editorCommon.IDiffEditorModel | null;
|
||||
|
||||
createViewModel(model: editorCommon.IDiffEditorModel): editorCommon.IDiffEditorViewModel;
|
||||
|
||||
/**
|
||||
* Sets the current model attached to this editor.
|
||||
* If the previous model was created by the editor via the value key in the options
|
||||
@@ -1172,7 +1167,7 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
* will not be destroyed.
|
||||
* It is safe to call setModel(null) to simply detach the current model from the editor.
|
||||
*/
|
||||
setModel(model: editorCommon.IDiffEditorModel | null): void;
|
||||
setModel(model: editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null): void;
|
||||
|
||||
/**
|
||||
* Get the `original` editor.
|
||||
@@ -1195,18 +1190,6 @@ export interface IDiffEditor extends editorCommon.IEditor {
|
||||
*/
|
||||
getDiffComputationResult(): IDiffComputationResult | null;
|
||||
|
||||
/**
|
||||
* Get information based on computed diff about a line number from the original model.
|
||||
* If the diff computation is not finished or the model is missing, will return null.
|
||||
*/
|
||||
getDiffLineInformationForOriginal(lineNumber: number): IDiffLineInformation | null;
|
||||
|
||||
/**
|
||||
* Get information based on computed diff about a line number from the modified model.
|
||||
* If the diff computation is not finished or the model is missing, will return null.
|
||||
*/
|
||||
getDiffLineInformationForModified(lineNumber: number): IDiffLineInformation | null;
|
||||
|
||||
/**
|
||||
* Update the editor's options after the editor has been created.
|
||||
*/
|
||||
|
||||
@@ -488,7 +488,7 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE
|
||||
return this._modelData.model;
|
||||
}
|
||||
|
||||
public setModel(_model: ITextModel | editorCommon.IDiffEditorModel | null = null): void {
|
||||
public setModel(_model: ITextModel | editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null = null): void {
|
||||
const model = <ITextModel | null>_model;
|
||||
if (this._modelData === null && model === null) {
|
||||
// Current model is the new model
|
||||
|
||||
@@ -829,7 +829,20 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
};
|
||||
}
|
||||
|
||||
public setModel(model: editorCommon.IDiffEditorModel | null): void {
|
||||
public createViewModel(model: editorCommon.IDiffEditorModel): editorCommon.IDiffEditorViewModel {
|
||||
return {
|
||||
model,
|
||||
async waitForDiff() {
|
||||
// noop
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public setModel(model: editorCommon.IDiffEditorModel | editorCommon.IDiffEditorViewModel | null): void {
|
||||
if (model && 'model' in model) {
|
||||
model = model.model;
|
||||
}
|
||||
|
||||
// Guard us against partial null model
|
||||
if (model && (!model.original || !model.modified)) {
|
||||
throw new Error(!model.original ? 'DiffEditorWidget.setModel: Original model is null' : 'DiffEditorWidget.setModel: Modified model is null');
|
||||
@@ -1461,97 +1474,6 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
|
||||
this._doLayout();
|
||||
}
|
||||
|
||||
private _getLineChangeAtOrBeforeLineNumber(lineNumber: number, startLineNumberExtractor: (lineChange: ILineChange) => number): ILineChange | null {
|
||||
const lineChanges = (this._diffComputationResult ? this._diffComputationResult.changes : []);
|
||||
if (lineChanges.length === 0 || lineNumber < startLineNumberExtractor(lineChanges[0])) {
|
||||
// There are no changes or `lineNumber` is before the first change
|
||||
return null;
|
||||
}
|
||||
|
||||
let min = 0;
|
||||
let max = lineChanges.length - 1;
|
||||
while (min < max) {
|
||||
const mid = Math.floor((min + max) / 2);
|
||||
const midStart = startLineNumberExtractor(lineChanges[mid]);
|
||||
const midEnd = (mid + 1 <= max ? startLineNumberExtractor(lineChanges[mid + 1]) : Constants.MAX_SAFE_SMALL_INTEGER);
|
||||
|
||||
if (lineNumber < midStart) {
|
||||
max = mid - 1;
|
||||
} else if (lineNumber >= midEnd) {
|
||||
min = mid + 1;
|
||||
} else {
|
||||
// HIT!
|
||||
min = mid;
|
||||
max = mid;
|
||||
}
|
||||
}
|
||||
return lineChanges[min];
|
||||
}
|
||||
|
||||
private _getEquivalentLineForOriginalLineNumber(lineNumber: number): number {
|
||||
const lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.originalStartLineNumber);
|
||||
|
||||
if (!lineChange) {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
const originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);
|
||||
const modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);
|
||||
const lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);
|
||||
const lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);
|
||||
|
||||
|
||||
const delta = lineNumber - originalEquivalentLineNumber;
|
||||
|
||||
if (delta <= lineChangeOriginalLength) {
|
||||
return modifiedEquivalentLineNumber + Math.min(delta, lineChangeModifiedLength);
|
||||
}
|
||||
|
||||
return modifiedEquivalentLineNumber + lineChangeModifiedLength - lineChangeOriginalLength + delta;
|
||||
}
|
||||
|
||||
private _getEquivalentLineForModifiedLineNumber(lineNumber: number): number {
|
||||
const lineChange = this._getLineChangeAtOrBeforeLineNumber(lineNumber, (lineChange) => lineChange.modifiedStartLineNumber);
|
||||
|
||||
if (!lineChange) {
|
||||
return lineNumber;
|
||||
}
|
||||
|
||||
const originalEquivalentLineNumber = lineChange.originalStartLineNumber + (lineChange.originalEndLineNumber > 0 ? -1 : 0);
|
||||
const modifiedEquivalentLineNumber = lineChange.modifiedStartLineNumber + (lineChange.modifiedEndLineNumber > 0 ? -1 : 0);
|
||||
const lineChangeOriginalLength = (lineChange.originalEndLineNumber > 0 ? (lineChange.originalEndLineNumber - lineChange.originalStartLineNumber + 1) : 0);
|
||||
const lineChangeModifiedLength = (lineChange.modifiedEndLineNumber > 0 ? (lineChange.modifiedEndLineNumber - lineChange.modifiedStartLineNumber + 1) : 0);
|
||||
|
||||
|
||||
const delta = lineNumber - modifiedEquivalentLineNumber;
|
||||
|
||||
if (delta <= lineChangeModifiedLength) {
|
||||
return originalEquivalentLineNumber + Math.min(delta, lineChangeOriginalLength);
|
||||
}
|
||||
|
||||
return originalEquivalentLineNumber + lineChangeOriginalLength - lineChangeModifiedLength + delta;
|
||||
}
|
||||
|
||||
public getDiffLineInformationForOriginal(lineNumber: number): editorBrowser.IDiffLineInformation | null {
|
||||
if (!this._diffComputationResult) {
|
||||
// Cannot answer that which I don't know
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
equivalentLineNumber: this._getEquivalentLineForOriginalLineNumber(lineNumber)
|
||||
};
|
||||
}
|
||||
|
||||
public getDiffLineInformationForModified(lineNumber: number): editorBrowser.IDiffLineInformation | null {
|
||||
if (!this._diffComputationResult) {
|
||||
// Cannot answer that which I don't know
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
equivalentLineNumber: this._getEquivalentLineForModifiedLineNumber(lineNumber)
|
||||
};
|
||||
}
|
||||
|
||||
public goToDiff(target: 'previous' | 'next'): void {
|
||||
if (target === 'next') {
|
||||
this._diffNavigator?.next();
|
||||
|
||||
@@ -3,18 +3,30 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { MarkdownString } from 'vs/base/common/htmlContent';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { localize } from 'vs/nls';
|
||||
import { registerIcon } from 'vs/platform/theme/common/iconRegistry';
|
||||
|
||||
export const diffInsertIcon = registerIcon('diff-insert', Codicon.add, localize('diffInsertIcon', 'Line decoration for inserts in the diff editor.'));
|
||||
export const diffRemoveIcon = registerIcon('diff-remove', Codicon.remove, localize('diffRemoveIcon', 'Line decoration for removals in the diff editor.'));
|
||||
|
||||
export const diffFullLineAddDecoration = ModelDecorationOptions.register({
|
||||
className: 'line-insert',
|
||||
description: 'line-insert',
|
||||
isWholeLine: true,
|
||||
linesDecorationsClassName: 'insert-sign ' + ThemeIcon.asClassName(diffInsertIcon),
|
||||
marginClassName: 'gutter-insert',
|
||||
});
|
||||
|
||||
export const diffFullLineDeleteDecoration = ModelDecorationOptions.register({
|
||||
className: 'line-delete',
|
||||
description: 'line-delete',
|
||||
isWholeLine: true,
|
||||
linesDecorationsClassName: 'delete-sign ' + ThemeIcon.asClassName(diffRemoveIcon),
|
||||
marginClassName: 'gutter-delete',
|
||||
});
|
||||
|
||||
export const diffAddDecoration = ModelDecorationOptions.register({
|
||||
@@ -26,3 +38,10 @@ export const diffDeleteDecoration = ModelDecorationOptions.register({
|
||||
className: 'char-delete',
|
||||
description: 'char-delete',
|
||||
});
|
||||
|
||||
export const arrowRevertChange = ModelDecorationOptions.register({
|
||||
description: 'diff-editor-arrow-revert-change',
|
||||
glyphMarginHoverMessage: new MarkdownString(undefined, { isTrusted: true, supportThemeIcons: true }).appendMarkdown(localize('revertChangeHoverMessage', 'Click to revert change')),
|
||||
glyphMarginClassName: 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight),
|
||||
zIndex: 10001,
|
||||
});
|
||||
|
||||
@@ -11,7 +11,7 @@ import { IDimension } from 'vs/editor/common/core/dimension';
|
||||
import { IPosition, Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ISelection, Selection } from 'vs/editor/common/core/selection';
|
||||
import { IEditor, IEditorAction, IEditorDecorationsCollection, IEditorModel, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IDiffEditorViewModel, IEditor, IEditorAction, IEditorDecorationsCollection, IEditorModel, IEditorViewState, ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDecorationsChangeAccessor, IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
|
||||
export abstract class DelegatingEditor extends Disposable implements IEditor {
|
||||
@@ -34,7 +34,7 @@ export abstract class DelegatingEditor extends Disposable implements IEditor {
|
||||
abstract saveViewState(): IEditorViewState | null;
|
||||
abstract restoreViewState(state: IEditorViewState | null): void;
|
||||
abstract getModel(): IEditorModel | null;
|
||||
abstract setModel(model: IEditorModel | null): void;
|
||||
abstract setModel(model: IEditorModel | null | IDiffEditorViewModel): void;
|
||||
|
||||
// #region editorBrowser.IDiffEditor: Delegating to modified Editor
|
||||
|
||||
|
||||
@@ -7,20 +7,21 @@ import { IBoundarySashes } from 'vs/base/browser/ui/sash/sash';
|
||||
import { findLast } from 'vs/base/common/arrays';
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { IObservable, ISettableObservable, derived, keepAlive, observableValue, waitForState } from 'vs/base/common/observable';
|
||||
import { disposableObservableValue } from 'vs/base/common/observableImpl/base';
|
||||
import { IObservable, ISettableObservable, autorun, derived, keepAlive, observableValue } from 'vs/base/common/observable';
|
||||
import { disposableObservableValue, transaction } from 'vs/base/common/observableImpl/base';
|
||||
import { derivedWithStore } from 'vs/base/common/observableImpl/derived';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { Constants } from 'vs/base/common/uint';
|
||||
import 'vs/css!./style';
|
||||
import { IEditorConstructionOptions } from 'vs/editor/browser/config/editorConfiguration';
|
||||
import { ICodeEditor, IDiffEditor, IDiffEditorConstructionOptions, IDiffLineInformation } from 'vs/editor/browser/editorBrowser';
|
||||
import { ICodeEditor, IDiffEditor, IDiffEditorConstructionOptions, IMouseTargetViewZone } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorExtensionsRegistry, IDiffEditorContributionDescription } from 'vs/editor/browser/editorExtensions';
|
||||
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
|
||||
import { CodeEditorWidget, ICodeEditorWidgetOptions } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { IDiffCodeEditorWidgetOptions } from 'vs/editor/browser/widget/diffEditorWidget';
|
||||
import { diffAddDecoration, diffDeleteDecoration, diffFullLineAddDecoration, diffFullLineDeleteDecoration } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
|
||||
import { arrowRevertChange, diffAddDecoration, diffDeleteDecoration, diffFullLineAddDecoration, diffFullLineDeleteDecoration } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
|
||||
import { DiffEditorSash } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorSash';
|
||||
import { ViewZoneAlignment } from 'vs/editor/browser/widget/diffEditorWidget2/lineAlignment';
|
||||
import { ViewZoneManager } from 'vs/editor/browser/widget/diffEditorWidget2/lineAlignment';
|
||||
import { MovedBlocksLinesPart } from 'vs/editor/browser/widget/diffEditorWidget2/movedBlocksLines';
|
||||
import { OverviewRulerPart } from 'vs/editor/browser/widget/diffEditorWidget2/overviewRulerPart';
|
||||
import { UnchangedRangesFeature } from 'vs/editor/browser/widget/diffEditorWidget2/unchangedRanges';
|
||||
@@ -31,7 +32,7 @@ import { IDimension } from 'vs/editor/common/core/dimension';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IDiffComputationResult, ILineChange } from 'vs/editor/common/diff/smartLinesDiffComputer';
|
||||
import { EditorType, IContentSizeChangedEvent, IDiffEditorModel, IDiffEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { EditorType, IContentSizeChangedEvent, IDiffEditorModel, IDiffEditorViewModel, IDiffEditorViewState } from 'vs/editor/common/editorCommon';
|
||||
import { IModelDeltaDecoration } from 'vs/editor/common/model';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
@@ -39,6 +40,8 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti
|
||||
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
|
||||
import { DelegatingEditor } from './delegatingEditorImpl';
|
||||
import { DiffMapping, DiffModel } from './diffModel';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
|
||||
const diffEditorDefaultOptions: ValidDiffEditorBaseOptions = {
|
||||
enableSplitViewResizing: true,
|
||||
@@ -79,7 +82,8 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
);
|
||||
private readonly _rootSizeObserver: ObservableElementSizeObserver;
|
||||
private readonly _options: ISettableObservable<ValidDiffEditorBaseOptions>;
|
||||
private readonly _sash: DiffEditorSash;
|
||||
private readonly _sash: IObservable<DiffEditorSash | undefined>;
|
||||
private readonly _boundarySashes = observableValue<IBoundarySashes | undefined>('boundarySashes', undefined);
|
||||
private readonly _renderOverviewRuler: IObservable<boolean>;
|
||||
|
||||
constructor(
|
||||
@@ -114,18 +118,42 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
this._register(applyObservableDecorations(this._modifiedEditor, this._decorations.map(d => d?.modifiedDecorations || [])));
|
||||
|
||||
this._renderOverviewRuler = this._options.map(o => o.renderOverviewRuler);
|
||||
this._sash = this._register(new DiffEditorSash(
|
||||
this._options.map(o => o.enableSplitViewResizing),
|
||||
this._options.map(o => o.splitViewDefaultRatio),
|
||||
this.elements.root,
|
||||
{
|
||||
height: this._rootSizeObserver.height,
|
||||
width: this._rootSizeObserver.width.map((w, reader) => w - (this._renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)),
|
||||
this._sash = derivedWithStore('sash', (reader, store) => {
|
||||
const showSash = this._options.read(reader).renderSideBySide;
|
||||
this.elements.root.classList.toggle('side-by-side', showSash);
|
||||
if (!showSash) {
|
||||
return undefined;
|
||||
}
|
||||
));
|
||||
const result = store.add(new DiffEditorSash(
|
||||
this._options.map(o => o.enableSplitViewResizing),
|
||||
this._options.map(o => o.splitViewDefaultRatio),
|
||||
this.elements.root,
|
||||
{
|
||||
height: this._rootSizeObserver.height,
|
||||
width: this._rootSizeObserver.width.map((w, reader) => w - (this._renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0)),
|
||||
}
|
||||
));
|
||||
store.add(autorun('setBoundarySashes', reader => {
|
||||
const boundarySashes = this._boundarySashes.read(reader);
|
||||
if (boundarySashes) {
|
||||
result.setBoundarySashes(boundarySashes);
|
||||
}
|
||||
}));
|
||||
return result;
|
||||
});
|
||||
this._register(keepAlive(this._sash, true));
|
||||
|
||||
this._register(new UnchangedRangesFeature(this._originalEditor, this._modifiedEditor, this._diffModel));
|
||||
this._register(new ViewZoneAlignment(this._originalEditor, this._modifiedEditor, this._diffModel));
|
||||
this._register(
|
||||
this._instantiationService.createInstance(
|
||||
ViewZoneManager,
|
||||
this._originalEditor,
|
||||
this._modifiedEditor,
|
||||
this._diffModel,
|
||||
this._options.map((o) => o.renderSideBySide),
|
||||
this
|
||||
)
|
||||
);
|
||||
|
||||
this._register(this._instantiationService.createInstance(OverviewRulerPart,
|
||||
this._originalEditor,
|
||||
@@ -157,17 +185,19 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
private readonly _layoutInfo = derived('modifiedEditorLayoutInfo', (reader) => {
|
||||
const width = this._rootSizeObserver.width.read(reader);
|
||||
const height = this._rootSizeObserver.height.read(reader);
|
||||
const sashLeft = this._sash.sashLeft.read(reader);
|
||||
const sashLeft = this._sash.read(reader)?.sashLeft.read(reader);
|
||||
|
||||
this.elements.original.style.width = sashLeft + 'px';
|
||||
const originalWidth = sashLeft ?? Math.max(5, this._originalEditor.getLayoutInfo().decorationsLeft);
|
||||
|
||||
this.elements.original.style.width = originalWidth + 'px';
|
||||
this.elements.original.style.left = '0px';
|
||||
|
||||
this.elements.modified.style.width = (width - sashLeft) + 'px';
|
||||
this.elements.modified.style.left = sashLeft + 'px';
|
||||
this.elements.modified.style.width = (width - originalWidth) + 'px';
|
||||
this.elements.modified.style.left = originalWidth + 'px';
|
||||
|
||||
this._originalEditor.layout({ width: sashLeft, height: height });
|
||||
this._originalEditor.layout({ width: originalWidth, height: height });
|
||||
this._modifiedEditor.layout({
|
||||
width: width - sashLeft -
|
||||
width: width - originalWidth -
|
||||
(this._renderOverviewRuler.read(reader) ? OverviewRulerPart.ENTIRE_DIFF_OVERVIEW_WIDTH : 0),
|
||||
height
|
||||
});
|
||||
@@ -210,6 +240,10 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
originalDecorations.push({ range: i.originalRange, options: diffDeleteDecoration });
|
||||
modifiedDecorations.push({ range: i.modifiedRange, options: diffAddDecoration });
|
||||
}
|
||||
|
||||
if (!m.lineRangeMapping.modifiedRange.isEmpty) {
|
||||
modifiedDecorations.push({ range: Range.fromPositions(new Position(m.lineRangeMapping.modifiedRange.startLineNumber, 1)), options: arrowRevertChange });
|
||||
}
|
||||
}
|
||||
|
||||
if (currentMove) {
|
||||
@@ -272,7 +306,6 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
if (!m) { return; }
|
||||
|
||||
const movedText = m.diff.get()!.movedTexts.find(m => m.lineRangeMapping.originalRange.contains(e.position.lineNumber));
|
||||
|
||||
m.syncedMovedTexts.set(movedText, undefined);
|
||||
}));
|
||||
return editor;
|
||||
@@ -288,28 +321,35 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
if (!m) { return; }
|
||||
|
||||
const movedText = m.diff.get()!.movedTexts.find(m => m.lineRangeMapping.modifiedRange.contains(e.position.lineNumber));
|
||||
|
||||
m.syncedMovedTexts.set(movedText, undefined);
|
||||
}));
|
||||
// Revert change when an arrow is clicked.
|
||||
/*TODO
|
||||
this._register(editor.onMouseDown(event => {
|
||||
if (!event.event.rightButton && event.target.position && event.target.element?.className.includes('arrow-revert-change')) {
|
||||
const lineNumber = event.target.position.lineNumber;
|
||||
const viewZone = event.target as editorBrowser.IMouseTargetViewZone | undefined;
|
||||
const change = this._diffComputationResult?.changes.find(c =>
|
||||
// delete change
|
||||
viewZone?.detail.afterLineNumber === c.modifiedStartLineNumber ||
|
||||
// other changes
|
||||
(c.modifiedEndLineNumber > 0 && c.modifiedStartLineNumber === lineNumber));
|
||||
if (change) {
|
||||
this.revertChange(change);
|
||||
const viewZone = event.target as IMouseTargetViewZone | undefined;
|
||||
|
||||
const model = this._diffModel.get();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
const diffs = model.diff.get()?.mappings;
|
||||
if (!diffs) {
|
||||
return;
|
||||
}
|
||||
const diff = diffs.find(d =>
|
||||
viewZone?.detail.afterLineNumber === d.lineRangeMapping.modifiedRange.startLineNumber - 1 ||
|
||||
d.lineRangeMapping.modifiedRange.startLineNumber === lineNumber
|
||||
);
|
||||
if (!diff) {
|
||||
return;
|
||||
}
|
||||
this.revert(diff.lineRangeMapping);
|
||||
|
||||
event.event.stopPropagation();
|
||||
this._updateDecorations();
|
||||
return;
|
||||
}
|
||||
}));*/
|
||||
}));
|
||||
|
||||
return editor;
|
||||
}
|
||||
@@ -425,31 +465,44 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
return this._originalEditor.hasTextFocus() || this._modifiedEditor.hasTextFocus();
|
||||
}
|
||||
|
||||
override saveViewState(): IDiffEditorViewState | null {
|
||||
return null;
|
||||
//throw new Error('Method not implemented.');
|
||||
public override saveViewState(): IDiffEditorViewState {
|
||||
const originalViewState = this._originalEditor.saveViewState();
|
||||
const modifiedViewState = this._modifiedEditor.saveViewState();
|
||||
return {
|
||||
original: originalViewState,
|
||||
modified: modifiedViewState
|
||||
};
|
||||
}
|
||||
|
||||
override restoreViewState(state: IDiffEditorViewState | null): void {
|
||||
//throw new Error('Method not implemented.');
|
||||
public override restoreViewState(s: IDiffEditorViewState): void {
|
||||
if (s && s.original && s.modified) {
|
||||
const diffEditorState = s as IDiffEditorViewState;
|
||||
this._originalEditor.restoreViewState(diffEditorState.original);
|
||||
this._modifiedEditor.restoreViewState(diffEditorState.modified);
|
||||
}
|
||||
}
|
||||
|
||||
override getModel(): IDiffEditorModel | null { return this._model.get(); }
|
||||
|
||||
override setModel(model: IDiffEditorModel | null): void {
|
||||
this._originalEditor.setModel(model ? model.original : null);
|
||||
this._modifiedEditor.setModel(model ? model.modified : null);
|
||||
|
||||
this._model.set(model, undefined);
|
||||
|
||||
this._diffModel.set(model ? new DiffModel(
|
||||
public createViewModel(model: IDiffEditorModel): IDiffEditorViewModel {
|
||||
return new DiffModel(
|
||||
model,
|
||||
this._options.map(o => o.ignoreTrimWhitespace),
|
||||
this._options.map(o => o.maxComputationTime),
|
||||
this._options.map(o => o.experimental.collapseUnchangedRegions!),
|
||||
this._options.map(o => o.experimental.showMoves!),
|
||||
this._options.map(o => o.experimental.showMoves! && o.renderSideBySide),
|
||||
this._instantiationService.createInstance(WorkerBasedDocumentDiffProvider, this._options.get())
|
||||
) : undefined, undefined);
|
||||
);
|
||||
}
|
||||
|
||||
override getModel(): IDiffEditorModel | null { return this._model.get(); }
|
||||
|
||||
override setModel(model: IDiffEditorModel | null | IDiffEditorViewModel): void {
|
||||
const vm = model ? ('model' in model) ? model : this.createViewModel(model) : undefined;
|
||||
this._originalEditor.setModel(vm ? vm.model.original : null);
|
||||
this._modifiedEditor.setModel(vm ? vm.model.modified : null);
|
||||
transaction(tx => {
|
||||
this._model.set(vm?.model ?? null, tx);
|
||||
this._diffModel.set(vm as (DiffModel | undefined), tx);
|
||||
});
|
||||
}
|
||||
|
||||
override updateOptions(_newOptions: IDiffEditorOptions): void {
|
||||
@@ -465,12 +518,11 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
getModifiedEditor(): ICodeEditor { return this._modifiedEditor; }
|
||||
|
||||
setBoundarySashes(sashes: IBoundarySashes): void {
|
||||
this._sash.setBoundarySashes(sashes);
|
||||
this._boundarySashes.set(sashes, undefined);
|
||||
}
|
||||
|
||||
readonly onDidUpdateDiff: Event<void> = e => {
|
||||
return { dispose: () => { } };
|
||||
};
|
||||
private readonly _diffValue = this._diffModel.map((m, r) => m?.diff.read(r));
|
||||
readonly onDidUpdateDiff: Event<void> = Event.fromObservableLight(this._diffValue);
|
||||
|
||||
get ignoreTrimWhitespace(): boolean {
|
||||
return this._options.get().ignoreTrimWhitespace;
|
||||
@@ -484,21 +536,84 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
return this._options.get().renderSideBySide;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use `this.getDiffComputationResult().changes2` instead.
|
||||
*/
|
||||
getLineChanges(): ILineChange[] | null {
|
||||
return null;
|
||||
//throw new Error('Method not implemented.');
|
||||
const diffState = this._diffModel.get()?.diff.get();
|
||||
if (!diffState) {
|
||||
return null;
|
||||
}
|
||||
return diffState.mappings.map(x => {
|
||||
const m = x.lineRangeMapping;
|
||||
let originalStartLineNumber: number;
|
||||
let originalEndLineNumber: number;
|
||||
let modifiedStartLineNumber: number;
|
||||
let modifiedEndLineNumber: number;
|
||||
let innerChanges = m.innerChanges;
|
||||
|
||||
if (m.originalRange.isEmpty) {
|
||||
// Insertion
|
||||
originalStartLineNumber = m.originalRange.startLineNumber - 1;
|
||||
originalEndLineNumber = 0;
|
||||
innerChanges = undefined;
|
||||
} else {
|
||||
originalStartLineNumber = m.originalRange.startLineNumber;
|
||||
originalEndLineNumber = m.originalRange.endLineNumberExclusive - 1;
|
||||
}
|
||||
|
||||
if (m.modifiedRange.isEmpty) {
|
||||
// Deletion
|
||||
modifiedStartLineNumber = m.modifiedRange.startLineNumber - 1;
|
||||
modifiedEndLineNumber = 0;
|
||||
innerChanges = undefined;
|
||||
} else {
|
||||
modifiedStartLineNumber = m.modifiedRange.startLineNumber;
|
||||
modifiedEndLineNumber = m.modifiedRange.endLineNumberExclusive - 1;
|
||||
}
|
||||
|
||||
return {
|
||||
originalStartLineNumber,
|
||||
originalEndLineNumber,
|
||||
modifiedStartLineNumber,
|
||||
modifiedEndLineNumber,
|
||||
charChanges: innerChanges?.map(m => ({
|
||||
originalStartLineNumber: m.originalRange.startLineNumber,
|
||||
originalStartColumn: m.originalRange.startColumn,
|
||||
originalEndLineNumber: m.originalRange.endLineNumber,
|
||||
originalEndColumn: m.originalRange.endColumn,
|
||||
modifiedStartLineNumber: m.modifiedRange.startLineNumber,
|
||||
modifiedStartColumn: m.modifiedRange.startColumn,
|
||||
modifiedEndLineNumber: m.modifiedRange.endLineNumber,
|
||||
modifiedEndColumn: m.modifiedRange.endColumn,
|
||||
}))
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
getDiffComputationResult(): IDiffComputationResult | null {
|
||||
return null;
|
||||
//throw new Error('Method not implemented.');
|
||||
const diffState = this._diffModel.get()?.diff.get();
|
||||
if (!diffState) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
changes: this.getLineChanges()!,
|
||||
changes2: diffState.mappings.map(m => m.lineRangeMapping),
|
||||
identical: diffState.identical,
|
||||
quitEarly: diffState.quitEarly,
|
||||
};
|
||||
}
|
||||
getDiffLineInformationForOriginal(lineNumber: number): IDiffLineInformation | null {
|
||||
return null;
|
||||
//throw new Error('Method not implemented.');
|
||||
}
|
||||
getDiffLineInformationForModified(lineNumber: number): IDiffLineInformation | null {
|
||||
return null;
|
||||
//throw new Error('Method not implemented.');
|
||||
|
||||
public revert(diff: LineRangeMapping): void {
|
||||
const model = this._model.get();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
const originalText = model.original.getValueInRange(diff.originalRange.toExclusiveRange());
|
||||
this._modifiedEditor.executeEdits('diffEditor', [
|
||||
{ range: diff.modifiedRange.toExclusiveRange(), text: originalText }
|
||||
]);
|
||||
}
|
||||
|
||||
private _goTo(diff: DiffMapping): void {
|
||||
@@ -529,7 +644,7 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
return;
|
||||
}
|
||||
// wait for the diff computation to finish
|
||||
waitForState(diffModel.isDiffUpToDate, s => s).then(() => {
|
||||
this.waitForDiff().then(() => {
|
||||
const diffs = diffModel.diff.get()?.mappings;
|
||||
if (!diffs || diffs.length === 0) {
|
||||
return;
|
||||
@@ -537,6 +652,15 @@ export class DiffEditorWidget2 extends DelegatingEditor implements IDiffEditor {
|
||||
this._goTo(diffs[0]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public async waitForDiff(): Promise<void> {
|
||||
const diffModel = this._diffModel.get();
|
||||
if (!diffModel) {
|
||||
return;
|
||||
}
|
||||
await diffModel.waitForDiff();
|
||||
}
|
||||
}
|
||||
|
||||
function validateDiffEditorOptions(options: Readonly<IDiffEditorOptions>, defaults: ValidDiffEditorBaseOptions): ValidDiffEditorBaseOptions {
|
||||
|
||||
@@ -5,27 +5,32 @@
|
||||
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IObservable, IReader, ITransaction, derived, observableSignal, observableSignalFromEvent, observableValue, transaction } from 'vs/base/common/observable';
|
||||
import { IObservable, IReader, ITransaction, derived, observableSignal, observableSignalFromEvent, observableValue, transaction, waitForState } from 'vs/base/common/observable';
|
||||
import { autorunWithStore2 } from 'vs/base/common/observableImpl/autorun';
|
||||
import { isDefined } from 'vs/base/common/types';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IDocumentDiff, IDocumentDiffProvider } from 'vs/editor/common/diff/documentDiffProvider';
|
||||
import { LineRangeMapping, MovedText, RangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { LineRangeMapping, MovedText, RangeMapping, SimpleLineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { lineRangeMappingFromRangeMappings } from 'vs/editor/common/diff/standardLinesDiffComputer';
|
||||
import { IDiffEditorModel } from 'vs/editor/common/editorCommon';
|
||||
import { IDiffEditorModel, IDiffEditorViewModel } from 'vs/editor/common/editorCommon';
|
||||
import { ITextModel } from 'vs/editor/common/model';
|
||||
import { TextEditInfo } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/beforeEditPositionMapper';
|
||||
import { combineTextEditInfos } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/combineTextEditInfos';
|
||||
import { lengthAdd, lengthDiffNonNegative, lengthOfRange, lengthToPosition, lengthZero, positionToLength } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
|
||||
import { lengthAdd, lengthDiffNonNegative, lengthGetLineCount, lengthOfRange, lengthToPosition, lengthZero, positionToLength } from 'vs/editor/common/model/bracketPairsTextModelPart/bracketPairsTree/length';
|
||||
|
||||
export class DiffModel extends Disposable {
|
||||
export class DiffModel extends Disposable implements IDiffEditorViewModel {
|
||||
private readonly _isDiffUpToDate = observableValue<boolean>('isDiffUpToDate', false);
|
||||
public readonly isDiffUpToDate: IObservable<boolean> = this._isDiffUpToDate;
|
||||
|
||||
private _lastDiff: IDocumentDiff | undefined;
|
||||
private readonly _diff = observableValue<DiffState | undefined>('diff', undefined);
|
||||
public readonly diff: IObservable<DiffState | undefined> = this._diff;
|
||||
|
||||
private readonly _unchangedRegions = observableValue<{ regions: UnchangedRegion[]; originalDecorationIds: string[]; modifiedDecorationIds: string[] }>('unchangedRegion', { regions: [], originalDecorationIds: [], modifiedDecorationIds: [] });
|
||||
private readonly _unchangedRegions = observableValue<{ regions: UnchangedRegion[]; originalDecorationIds: string[]; modifiedDecorationIds: string[] }>(
|
||||
'unchangedRegion',
|
||||
{ regions: [], originalDecorationIds: [], modifiedDecorationIds: [] }
|
||||
);
|
||||
public readonly unchangedRegions: IObservable<UnchangedRegion[]> = derived('unchangedRegions', r =>
|
||||
this._hideUnchangedRegions.read(r) ? this._unchangedRegions.read(r).regions : []
|
||||
);
|
||||
@@ -33,7 +38,7 @@ export class DiffModel extends Disposable {
|
||||
public readonly syncedMovedTexts = observableValue<MovedText | undefined>('syncedMovedText', undefined);
|
||||
|
||||
constructor(
|
||||
model: IDiffEditorModel,
|
||||
public readonly model: IDiffEditorModel,
|
||||
ignoreTrimWhitespace: IObservable<boolean>,
|
||||
maxComputationTimeMs: IObservable<number>,
|
||||
private readonly _hideUnchangedRegions: IObservable<boolean>,
|
||||
@@ -50,11 +55,14 @@ export class DiffModel extends Disposable {
|
||||
if (!diff) {
|
||||
return;
|
||||
}
|
||||
/*const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._diff.set(
|
||||
applyModifiedEdits(diff, textEdits, model.original, model.modified),
|
||||
undefined
|
||||
);*/
|
||||
if (!this._showMoves.get()) {
|
||||
const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._lastDiff = applyModifiedEdits(this._lastDiff!, textEdits, model.original, model.modified);
|
||||
this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined);
|
||||
}
|
||||
|
||||
debouncer.schedule();
|
||||
}));
|
||||
this._register(model.original.onDidChangeContent((e) => {
|
||||
@@ -62,11 +70,13 @@ export class DiffModel extends Disposable {
|
||||
if (!diff) {
|
||||
return;
|
||||
}
|
||||
/*const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._diff.set(
|
||||
applyOriginalEdits(diff, textEdits, model.original, model.modified),
|
||||
undefined
|
||||
);*/
|
||||
if (!this._showMoves.get()) {
|
||||
const textEdits = TextEditInfo.fromModelContentChanges(e.changes);
|
||||
this._lastDiff = applyOriginalEdits(this._lastDiff!, textEdits, model.original, model.modified);
|
||||
this._diff.set(DiffState.fromDiffResult(this._lastDiff), undefined);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, undefined);
|
||||
}
|
||||
debouncer.schedule();
|
||||
}));
|
||||
|
||||
@@ -137,8 +147,11 @@ export class DiffModel extends Disposable {
|
||||
);
|
||||
|
||||
transaction(tx => {
|
||||
this._lastDiff = result;
|
||||
this._diff.set(DiffState.fromDiffResult(result), tx);
|
||||
this._isDiffUpToDate.set(true, tx);
|
||||
const currentSyncedMovedText = this.syncedMovedTexts.get();
|
||||
this.syncedMovedTexts.set(currentSyncedMovedText ? this._lastDiff.moves.find(m => m.lineRangeMapping.modifiedRange.intersect(currentSyncedMovedText.lineRangeMapping.modifiedRange)) : undefined, tx);
|
||||
|
||||
this._unchangedRegions.set(
|
||||
{
|
||||
@@ -152,7 +165,7 @@ export class DiffModel extends Disposable {
|
||||
}));
|
||||
}
|
||||
|
||||
public revealModifiedLine(lineNumber: number, tx: ITransaction): void {
|
||||
public ensureModifiedLineIsVisible(lineNumber: number, tx: ITransaction): void {
|
||||
const unchangedRegions = this._unchangedRegions.get().regions;
|
||||
for (const r of unchangedRegions) {
|
||||
if (r.getHiddenModifiedRange(undefined).contains(lineNumber)) {
|
||||
@@ -162,7 +175,7 @@ export class DiffModel extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
public revealOriginalLine(lineNumber: number, tx: ITransaction): void {
|
||||
public ensureOriginalLineIsVisible(lineNumber: number, tx: ITransaction): void {
|
||||
const unchangedRegions = this._unchangedRegions.get().regions;
|
||||
for (const r of unchangedRegions) {
|
||||
if (r.getHiddenOriginalRange(undefined).contains(lineNumber)) {
|
||||
@@ -171,19 +184,27 @@ export class DiffModel extends Disposable {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public async waitForDiff(): Promise<void> {
|
||||
await waitForState(this.isDiffUpToDate, s => s);
|
||||
}
|
||||
}
|
||||
|
||||
export class DiffState {
|
||||
public static fromDiffResult(result: IDocumentDiff): DiffState {
|
||||
return new DiffState(
|
||||
result.changes.map(c => new DiffMapping(c)),
|
||||
result.moves || []
|
||||
result.moves || [],
|
||||
result.identical,
|
||||
result.quitEarly,
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly mappings: readonly DiffMapping[],
|
||||
public readonly movedTexts: readonly MovedText[],
|
||||
public readonly identical: boolean,
|
||||
public readonly quitEarly: boolean,
|
||||
) { }
|
||||
}
|
||||
|
||||
@@ -311,38 +332,17 @@ function applyOriginalEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
return diff;
|
||||
}
|
||||
|
||||
const diffTextEdits = diff.changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
positionToLength(c.modifiedRange.getStartPosition()),
|
||||
positionToLength(c.modifiedRange.getEndPosition()),
|
||||
lengthOfRange(c.originalRange).toLength(),
|
||||
)));
|
||||
|
||||
const combined = combineTextEditInfos(diffTextEdits, textEdits);
|
||||
|
||||
let lastModifiedEndOffset = lengthZero;
|
||||
let lastOriginalEndOffset = lengthZero;
|
||||
const rangeMappings = combined.map(c => {
|
||||
const originalStartOffset = lengthAdd(lastOriginalEndOffset, lengthDiffNonNegative(lastModifiedEndOffset, c.startOffset));
|
||||
lastModifiedEndOffset = c.endOffset;
|
||||
lastOriginalEndOffset = lengthAdd(originalStartOffset, c.newLength);
|
||||
|
||||
return new RangeMapping(
|
||||
Range.fromPositions(lengthToPosition(originalStartOffset), lengthToPosition(lastOriginalEndOffset)),
|
||||
Range.fromPositions(lengthToPosition(c.startOffset), lengthToPosition(c.endOffset)),
|
||||
);
|
||||
});
|
||||
|
||||
const changes = lineRangeMappingFromRangeMappings(
|
||||
rangeMappings,
|
||||
originalTextModel.getLinesContent(),
|
||||
modifiedTextModel.getLinesContent(),
|
||||
);
|
||||
const diff2 = flip(diff);
|
||||
const diff3 = applyModifiedEdits(diff2, textEdits, modifiedTextModel, originalTextModel);
|
||||
return flip(diff3);
|
||||
}
|
||||
|
||||
function flip(diff: IDocumentDiff): IDocumentDiff {
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves: [],
|
||||
changes: diff.changes.map(c => c.flip()),
|
||||
moves: diff.moves.map(m => m.flip()),
|
||||
identical: diff.identical,
|
||||
quitEarly: diff.quitEarly,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -351,7 +351,63 @@ function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
return diff;
|
||||
}
|
||||
|
||||
const diffTextEdits = diff.changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
const changes = applyModifiedEditsToLineRangeMappings(diff.changes, textEdits, originalTextModel, modifiedTextModel);
|
||||
|
||||
const moves = diff.moves.map(m => {
|
||||
const newModifiedRange = applyEditToLineRange(m.lineRangeMapping.modifiedRange, textEdits);
|
||||
return newModifiedRange ? new MovedText(
|
||||
new SimpleLineRangeMapping(m.lineRangeMapping.originalRange, newModifiedRange),
|
||||
applyModifiedEditsToLineRangeMappings(m.changes, textEdits, originalTextModel, modifiedTextModel),
|
||||
) : undefined;
|
||||
}).filter(isDefined);
|
||||
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves,
|
||||
};
|
||||
}
|
||||
|
||||
function applyEditToLineRange(range: LineRange, textEdits: TextEditInfo[]): LineRange | undefined {
|
||||
let rangeStartLineNumber = range.startLineNumber;
|
||||
let rangeEndLineNumberEx = range.endLineNumberExclusive;
|
||||
|
||||
for (let i = textEdits.length - 1; i >= 0; i--) {
|
||||
const textEdit = textEdits[i];
|
||||
const textEditStartLineNumber = lengthGetLineCount(textEdit.startOffset) + 1;
|
||||
const textEditEndLineNumber = lengthGetLineCount(textEdit.endOffset) + 1;
|
||||
const newLengthLineCount = lengthGetLineCount(textEdit.newLength);
|
||||
const delta = newLengthLineCount - (textEditEndLineNumber - textEditStartLineNumber);
|
||||
|
||||
if (textEditEndLineNumber < rangeStartLineNumber) {
|
||||
// the text edit is before us
|
||||
rangeStartLineNumber += delta;
|
||||
rangeEndLineNumberEx += delta;
|
||||
} else if (textEditStartLineNumber > rangeEndLineNumberEx) {
|
||||
// the text edit is after us
|
||||
// NOOP
|
||||
} else if (textEditStartLineNumber < rangeStartLineNumber && rangeEndLineNumberEx < textEditEndLineNumber) {
|
||||
// the range is fully contained in the text edit
|
||||
return undefined;
|
||||
} else if (textEditStartLineNumber < rangeStartLineNumber && textEditEndLineNumber <= rangeEndLineNumberEx) {
|
||||
// the text edit ends inside our range
|
||||
rangeStartLineNumber = textEditEndLineNumber + 1;
|
||||
rangeStartLineNumber += delta;
|
||||
rangeEndLineNumberEx += delta;
|
||||
} else if (rangeStartLineNumber <= textEditStartLineNumber && textEditEndLineNumber < rangeStartLineNumber) {
|
||||
// the text edit starts inside our range
|
||||
rangeEndLineNumberEx = textEditStartLineNumber;
|
||||
} else {
|
||||
rangeEndLineNumberEx += delta;
|
||||
}
|
||||
}
|
||||
|
||||
return new LineRange(rangeStartLineNumber, rangeEndLineNumberEx);
|
||||
}
|
||||
|
||||
function applyModifiedEditsToLineRangeMappings(changes: readonly LineRangeMapping[], textEdits: TextEditInfo[], originalTextModel: ITextModel, modifiedTextModel: ITextModel): LineRangeMapping[] {
|
||||
const diffTextEdits = changes.flatMap(c => c.innerChanges!.map(c => new TextEditInfo(
|
||||
positionToLength(c.originalRange.getStartPosition()),
|
||||
positionToLength(c.originalRange.getEndPosition()),
|
||||
lengthOfRange(c.modifiedRange).toLength(),
|
||||
@@ -372,16 +428,10 @@ function applyModifiedEdits(diff: IDocumentDiff, textEdits: TextEditInfo[], orig
|
||||
);
|
||||
});
|
||||
|
||||
const changes = lineRangeMappingFromRangeMappings(
|
||||
const newChanges = lineRangeMappingFromRangeMappings(
|
||||
rangeMappings,
|
||||
originalTextModel.getLinesContent(),
|
||||
modifiedTextModel.getLinesContent(),
|
||||
);
|
||||
|
||||
return {
|
||||
identical: false,
|
||||
quitEarly: false,
|
||||
changes,
|
||||
moves: [],
|
||||
};
|
||||
return newChanges;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { addStandardDisposableListener, getDomNodePagePosition } from 'vs/base/browser/dom';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { isIOS } from 'vs/base/common/platform';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { EndOfLineSequence, ITextModel } from 'vs/editor/common/model';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export class InlineDiffDeletedCodeMargin extends Disposable {
|
||||
private readonly _diffActions: HTMLElement;
|
||||
|
||||
private _visibility: boolean = false;
|
||||
|
||||
get visibility(): boolean {
|
||||
return this._visibility;
|
||||
}
|
||||
|
||||
set visibility(_visibility: boolean) {
|
||||
if (this._visibility !== _visibility) {
|
||||
this._visibility = _visibility;
|
||||
|
||||
if (_visibility) {
|
||||
this._diffActions.style.visibility = 'visible';
|
||||
} else {
|
||||
this._diffActions.style.visibility = 'hidden';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _getViewZoneId: () => string,
|
||||
private readonly _marginDomNode: HTMLElement,
|
||||
private readonly _modifiedEditor: CodeEditorWidget,
|
||||
private readonly _diff: LineRangeMapping,
|
||||
private readonly _editor: DiffEditorWidget2,
|
||||
private readonly _viewLineCounts: number[],
|
||||
private readonly _originalTextModel: ITextModel,
|
||||
private readonly _contextMenuService: IContextMenuService,
|
||||
private readonly _clipboardService: IClipboardService,
|
||||
) {
|
||||
super();
|
||||
|
||||
// make sure the diff margin shows above overlay.
|
||||
this._marginDomNode.style.zIndex = '10';
|
||||
|
||||
this._diffActions = document.createElement('div');
|
||||
this._diffActions.className = ThemeIcon.asClassName(Codicon.lightBulb) + ' lightbulb-glyph';
|
||||
this._diffActions.style.position = 'absolute';
|
||||
const lineHeight = this._modifiedEditor.getOption(EditorOption.lineHeight);
|
||||
this._diffActions.style.right = '0px';
|
||||
this._diffActions.style.visibility = 'hidden';
|
||||
this._diffActions.style.height = `${lineHeight}px`;
|
||||
this._diffActions.style.lineHeight = `${lineHeight}px`;
|
||||
this._marginDomNode.appendChild(this._diffActions);
|
||||
|
||||
const actions: Action[] = [];
|
||||
const isDeletion = _diff.modifiedRange.isEmpty;
|
||||
|
||||
// default action
|
||||
actions.push(new Action(
|
||||
'diff.clipboard.copyDeletedContent',
|
||||
isDeletion
|
||||
? (_diff.originalRange.length > 1
|
||||
? localize('diff.clipboard.copyDeletedLinesContent.label', "Copy deleted lines")
|
||||
: localize('diff.clipboard.copyDeletedLinesContent.single.label', "Copy deleted line"))
|
||||
: (_diff.originalRange.length > 1
|
||||
? localize('diff.clipboard.copyChangedLinesContent.label', "Copy changed lines")
|
||||
: localize('diff.clipboard.copyChangedLinesContent.single.label', "Copy changed line")),
|
||||
undefined,
|
||||
true,
|
||||
async () => {
|
||||
const originalText = this._originalTextModel.getValueInRange(_diff.originalRange.toExclusiveRange());
|
||||
await this._clipboardService.writeText(originalText);
|
||||
}
|
||||
));
|
||||
|
||||
let currentLineNumberOffset = 0;
|
||||
let copyLineAction: Action | undefined = undefined;
|
||||
if (_diff.originalRange.length > 1) {
|
||||
copyLineAction = new Action(
|
||||
'diff.clipboard.copyDeletedLineContent',
|
||||
isDeletion
|
||||
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", _diff.originalRange.startLineNumber)
|
||||
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", _diff.originalRange.startLineNumber),
|
||||
undefined,
|
||||
true,
|
||||
async () => {
|
||||
let lineContent = this._originalTextModel.getLineContent(_diff.originalRange.startLineNumber + currentLineNumberOffset);
|
||||
if (lineContent === '') {
|
||||
// empty line -> new line
|
||||
const eof = this._originalTextModel.getEndOfLineSequence();
|
||||
lineContent = eof === EndOfLineSequence.LF ? '\n' : '\r\n';
|
||||
}
|
||||
await this._clipboardService.writeText(lineContent);
|
||||
}
|
||||
);
|
||||
|
||||
actions.push(copyLineAction);
|
||||
}
|
||||
|
||||
const readOnly = _modifiedEditor.getOption(EditorOption.readOnly);
|
||||
if (!readOnly) {
|
||||
actions.push(new Action('diff.inline.revertChange', localize('diff.inline.revertChange.label', "Revert this change"), undefined, true, async () => {
|
||||
this._editor.revert(this._diff);
|
||||
}));
|
||||
}
|
||||
|
||||
const useShadowDOM = _modifiedEditor.getOption(EditorOption.useShadowDOM) && !isIOS; // Do not use shadow dom on IOS #122035
|
||||
|
||||
const showContextMenu = (x: number, y: number) => {
|
||||
this._contextMenuService.showContextMenu({
|
||||
domForShadowRoot: useShadowDOM ? _modifiedEditor.getDomNode() ?? undefined : undefined,
|
||||
getAnchor: () => {
|
||||
return {
|
||||
x,
|
||||
y
|
||||
};
|
||||
},
|
||||
getActions: () => {
|
||||
if (copyLineAction) {
|
||||
copyLineAction.label =
|
||||
isDeletion
|
||||
? localize('diff.clipboard.copyDeletedLineContent.label', "Copy deleted line ({0})", _diff.originalRange.startLineNumber + currentLineNumberOffset)
|
||||
: localize('diff.clipboard.copyChangedLineContent.label', "Copy changed line ({0})", _diff.originalRange.startLineNumber + currentLineNumberOffset);
|
||||
}
|
||||
return actions;
|
||||
},
|
||||
autoSelectFirstItem: true
|
||||
});
|
||||
};
|
||||
|
||||
this._register(addStandardDisposableListener(this._diffActions, 'mousedown', e => {
|
||||
const { top, height } = getDomNodePagePosition(this._diffActions);
|
||||
const pad = Math.floor(lineHeight / 3);
|
||||
e.preventDefault();
|
||||
showContextMenu(e.posx, top + height + pad);
|
||||
}));
|
||||
|
||||
this._register(_modifiedEditor.onMouseMove((e: IEditorMouseEvent) => {
|
||||
if ((e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) && e.target.detail.viewZoneId === this._getViewZoneId()) {
|
||||
currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);
|
||||
this.visibility = true;
|
||||
} else {
|
||||
this.visibility = false;
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(_modifiedEditor.onMouseDown((e: IEditorMouseEvent) => {
|
||||
if (!e.event.rightButton) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (e.target.type === MouseTargetType.CONTENT_VIEW_ZONE || e.target.type === MouseTargetType.GUTTER_VIEW_ZONE) {
|
||||
const viewZoneId = e.target.detail.viewZoneId;
|
||||
|
||||
if (viewZoneId === this._getViewZoneId()) {
|
||||
e.event.preventDefault();
|
||||
currentLineNumberOffset = this._updateLightBulbPosition(this._marginDomNode, e.event.browserEvent.y, lineHeight);
|
||||
showContextMenu(e.event.posx, e.event.posy + lineHeight);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
private _updateLightBulbPosition(marginDomNode: HTMLElement, y: number, lineHeight: number): number {
|
||||
const { top } = getDomNodePagePosition(marginDomNode);
|
||||
const offset = y - top;
|
||||
const lineNumberOffset = Math.floor(offset / lineHeight);
|
||||
const newTop = lineNumberOffset * lineHeight;
|
||||
this._diffActions.style.top = `${newTop}px`;
|
||||
if (this._viewLineCounts) {
|
||||
let acc = 0;
|
||||
for (let i = 0; i < this._viewLineCounts.length; i++) {
|
||||
acc += this._viewLineCounts[i];
|
||||
if (lineNumberOffset < acc) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lineNumberOffset;
|
||||
}
|
||||
}
|
||||
@@ -3,27 +3,46 @@
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { $ } from 'vs/base/browser/dom';
|
||||
import { ArrayQueue } from 'vs/base/common/arrays';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IObservable, observableSignalFromEvent, derived, observableValue, observableFromEvent } from 'vs/base/common/observable';
|
||||
import { Codicon } from 'vs/base/common/codicons';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IObservable, derived, observableFromEvent, observableSignalFromEvent, observableValue } from 'vs/base/common/observable';
|
||||
import { autorun, autorunWithStore2 } from 'vs/base/common/observableImpl/autorun';
|
||||
import { ThemeIcon } from 'vs/base/common/themables';
|
||||
import { assertIsDefined } from 'vs/base/common/types';
|
||||
import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';
|
||||
import { IViewZone } from 'vs/editor/browser/editorBrowser';
|
||||
import { StableEditorScrollState } from 'vs/editor/browser/stableEditorScroll';
|
||||
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { diffDeleteDecoration, diffRemoveIcon } from 'vs/editor/browser/widget/diffEditorWidget2/decorations';
|
||||
import { DiffEditorWidget2 } from 'vs/editor/browser/widget/diffEditorWidget2/diffEditorWidget2';
|
||||
import { DiffMapping, DiffModel } from 'vs/editor/browser/widget/diffEditorWidget2/diffModel';
|
||||
import { InlineDiffDeletedCodeMargin } from 'vs/editor/browser/widget/diffEditorWidget2/inlineDiffDeletedCodeMargin';
|
||||
import { LineSource, RenderOptions, renderLines } from 'vs/editor/browser/widget/diffEditorWidget2/renderLines';
|
||||
import { animatedObservable, joinCombine } from 'vs/editor/browser/widget/diffEditorWidget2/utils';
|
||||
import { EditorOption } from 'vs/editor/common/config/editorOptions';
|
||||
import { LineRange } from 'vs/editor/common/core/lineRange';
|
||||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { LineRangeMapping } from 'vs/editor/common/diff/linesDiffComputer';
|
||||
import { ScrollType } from 'vs/editor/common/editorCommon';
|
||||
import { BackgroundTokenizationState } from 'vs/editor/common/tokenizationTextModelPart';
|
||||
import { InlineDecoration, InlineDecorationType } from 'vs/editor/common/viewModel';
|
||||
import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService';
|
||||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
|
||||
export class ViewZoneAlignment extends Disposable {
|
||||
private readonly _origExtraHeight = observableValue('origExtraHeight', 0);
|
||||
private readonly _modExtraHeight = observableValue('modExtraHeight', 0);
|
||||
|
||||
/**
|
||||
* Ensures both editors have the same height by aligning unchanged lines.
|
||||
* In inline view mode, inserts viewzones to show deleted code from the original text model in the modified code editor.
|
||||
* Synchronizes scrolling.
|
||||
*/
|
||||
export class ViewZoneManager extends Disposable {
|
||||
private readonly _originalTopPadding = observableValue('originalTopPadding', 0);
|
||||
private readonly _originalScrollTop: IObservable<number>;
|
||||
private readonly _originalScrollOffset = observableValue<number, boolean>('originalScrollOffset', 0);
|
||||
private readonly _originalScrollOffsetAnimated = animatedObservable(this._originalScrollOffset, this._store);
|
||||
|
||||
private readonly _modifiedTopPadding = observableValue('modifiedTopPadding', 0);
|
||||
private readonly _modifiedScrollTop: IObservable<number>;
|
||||
private readonly _modifiedScrollOffset = observableValue<number, boolean>('modifiedScrollOffset', 0);
|
||||
private readonly _modifiedScrollOffsetAnimated = animatedObservable(this._modifiedScrollOffset, this._store);
|
||||
@@ -32,45 +51,47 @@ export class ViewZoneAlignment extends Disposable {
|
||||
private readonly _originalEditor: CodeEditorWidget,
|
||||
private readonly _modifiedEditor: CodeEditorWidget,
|
||||
private readonly _diffModel: IObservable<DiffModel | undefined>,
|
||||
private readonly _renderSideBySide: IObservable<boolean>,
|
||||
private readonly _diffEditorWidget: DiffEditorWidget2,
|
||||
@IClipboardService private readonly _clipboardService: IClipboardService,
|
||||
@IContextMenuService private readonly _contextMenuService: IContextMenuService,
|
||||
) {
|
||||
super();
|
||||
|
||||
let isChangingViewZones = false;
|
||||
|
||||
const origViewZonesChanged = observableSignalFromEvent(
|
||||
const originalViewZonesChanged = observableSignalFromEvent(
|
||||
'origViewZonesChanged',
|
||||
e => this._originalEditor.onDidChangeViewZones((args) => { if (!isChangingViewZones) { e(args); } })
|
||||
);
|
||||
const modViewZonesChanged = observableSignalFromEvent(
|
||||
const modifiedViewZonesChanged = observableSignalFromEvent(
|
||||
'modViewZonesChanged',
|
||||
e => this._modifiedEditor.onDidChangeViewZones((args) => { if (!isChangingViewZones) { e(args); } })
|
||||
);
|
||||
|
||||
const originalModelTokenizationCompleted = this._diffModel.map(m =>
|
||||
m ? observableFromEvent(m.model.original.onDidChangeTokens, () => m.model.original.tokenization.backgroundTokenizationState === BackgroundTokenizationState.Completed) : undefined
|
||||
).map((m, reader) => m?.read(reader));
|
||||
|
||||
const alignmentViewZoneIdsOrig = new Set<string>();
|
||||
const alignmentViewZoneIdsMod = new Set<string>();
|
||||
|
||||
const alignments = derived<IRangeAlignment[] | null>('alignments', (reader) => {
|
||||
const alignments = derived<ILineRangeAlignment[] | null>('alignments', (reader) => {
|
||||
const diffModel = this._diffModel.read(reader);
|
||||
const diff = diffModel?.diff.read(reader);
|
||||
if (!diffModel || !diff) { return null; }
|
||||
|
||||
origViewZonesChanged.read(reader);
|
||||
modViewZonesChanged.read(reader);
|
||||
|
||||
originalViewZonesChanged.read(reader);
|
||||
modifiedViewZonesChanged.read(reader);
|
||||
return computeRangeAlignment(this._originalEditor, this._modifiedEditor, diff.mappings, alignmentViewZoneIdsOrig, alignmentViewZoneIdsMod);
|
||||
});
|
||||
|
||||
const alignmentsSyncedMovedText = derived<IRangeAlignment[] | null>('alignments', (reader) => {
|
||||
origViewZonesChanged.read(reader);
|
||||
modViewZonesChanged.read(reader);
|
||||
|
||||
const alignmentsSyncedMovedText = derived<ILineRangeAlignment[] | null>('alignments', (reader) => {
|
||||
const syncedMovedText = this._diffModel.read(reader)?.syncedMovedTexts.read(reader);
|
||||
if (!syncedMovedText) {
|
||||
return null;
|
||||
}
|
||||
if (!syncedMovedText) { return null; }
|
||||
originalViewZonesChanged.read(reader);
|
||||
modifiedViewZonesChanged.read(reader);
|
||||
const mappings = syncedMovedText.changes.map(c => new DiffMapping(c));
|
||||
|
||||
// TOD dont include alignments outside syncedMovedText
|
||||
// TODO dont include alignments outside syncedMovedText
|
||||
return computeRangeAlignment(this._originalEditor, this._modifiedEditor, mappings, alignmentViewZoneIdsOrig, alignmentViewZoneIdsMod);
|
||||
});
|
||||
|
||||
@@ -80,33 +101,139 @@ export class ViewZoneAlignment extends Disposable {
|
||||
return r;
|
||||
}
|
||||
|
||||
const alignmentViewZones = derived<{ orig: IViewZone[]; mod: IViewZone[] }>('alignment viewzones', (reader) => {
|
||||
const alignments_ = alignments.read(reader);
|
||||
const alignmentViewZonesDisposables = this._register(new DisposableStore());
|
||||
const alignmentViewZones = derived<{ orig: IViewZoneWithZoneId[]; mod: IViewZoneWithZoneId[] }>('alignment viewzones', (reader) => {
|
||||
alignmentViewZonesDisposables.clear();
|
||||
|
||||
const origViewZones: IViewZone[] = [];
|
||||
const modViewZones: IViewZone[] = [];
|
||||
const alignmentsVal = alignments.read(reader) || [];
|
||||
|
||||
const _modExtraHeight = this._modExtraHeight.read(reader);
|
||||
if (_modExtraHeight > 0) {
|
||||
const origViewZones: IViewZoneWithZoneId[] = [];
|
||||
const modViewZones: IViewZoneWithZoneId[] = [];
|
||||
|
||||
const modifiedTopPaddingVal = this._modifiedTopPadding.read(reader);
|
||||
if (modifiedTopPaddingVal > 0) {
|
||||
modViewZones.push({
|
||||
afterLineNumber: 0,
|
||||
domNode: document.createElement('div'),
|
||||
heightInPx: _modExtraHeight,
|
||||
heightInPx: modifiedTopPaddingVal,
|
||||
});
|
||||
}
|
||||
const _origExtraHeight = this._origExtraHeight.read(reader);
|
||||
if (_origExtraHeight > 0) {
|
||||
const originalTopPaddingVal = this._originalTopPadding.read(reader);
|
||||
if (originalTopPaddingVal > 0) {
|
||||
origViewZones.push({
|
||||
afterLineNumber: 0,
|
||||
domNode: document.createElement('div'),
|
||||
heightInPx: _origExtraHeight,
|
||||
heightInPx: originalTopPaddingVal,
|
||||
});
|
||||
}
|
||||
|
||||
const renderSideBySide = this._renderSideBySide.read(reader);
|
||||
|
||||
const deletedCodeLineBreaksComputer = !renderSideBySide ? this._modifiedEditor._getViewModel()?.createLineBreaksComputer() : undefined;
|
||||
if (deletedCodeLineBreaksComputer) {
|
||||
for (const a of alignmentsVal) {
|
||||
if (a.diff) {
|
||||
for (let i = a.originalRange.startLineNumber; i < a.originalRange.endLineNumberExclusive; i++) {
|
||||
deletedCodeLineBreaksComputer?.addRequest(this._originalEditor.getModel()!.getLineContent(i), null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const lineBreakData = deletedCodeLineBreaksComputer?.finalize() ?? [];
|
||||
let lineBreakDataIdx = 0;
|
||||
|
||||
const modLineHeight = this._modifiedEditor.getOption(EditorOption.lineHeight);
|
||||
|
||||
const syncedMovedText = this._diffModel.read(reader)?.syncedMovedTexts.read(reader);
|
||||
|
||||
if (alignments_) {
|
||||
for (const a of alignments_) {
|
||||
const mightContainNonBasicASCII = this._originalEditor.getModel()?.mightContainNonBasicASCII() ?? false;
|
||||
const mightContainRTL = this._originalEditor.getModel()?.mightContainRTL() ?? false;
|
||||
const renderOptions = RenderOptions.fromEditor(this._modifiedEditor);
|
||||
|
||||
for (const a of alignmentsVal) {
|
||||
if (a.diff && !renderSideBySide) {
|
||||
if (!a.originalRange.isEmpty) {
|
||||
originalModelTokenizationCompleted.read(reader); // Update view-zones once tokenization completes
|
||||
|
||||
const deletedCodeDomNode = document.createElement('div');
|
||||
deletedCodeDomNode.classList.add('view-lines', 'line-delete', 'monaco-mouse-cursor-text');
|
||||
const source = new LineSource(
|
||||
a.originalRange.mapToLineArray(l => this._originalEditor.getModel()!.tokenization.getLineTokens(l)),
|
||||
a.originalRange.mapToLineArray(_ => lineBreakData[lineBreakDataIdx++]),
|
||||
mightContainNonBasicASCII,
|
||||
mightContainRTL,
|
||||
);
|
||||
const decorations: InlineDecoration[] = [];
|
||||
for (const i of a.diff.innerChanges || []) {
|
||||
decorations.push(new InlineDecoration(
|
||||
i.originalRange.delta(-(a.diff.originalRange.startLineNumber - 1)),
|
||||
diffDeleteDecoration.className!,
|
||||
InlineDecorationType.Regular
|
||||
));
|
||||
}
|
||||
const result = renderLines(source, renderOptions, decorations, deletedCodeDomNode);
|
||||
|
||||
const marginDomNode = document.createElement('div');
|
||||
marginDomNode.className = 'inline-deleted-margin-view-zone';
|
||||
applyFontInfo(marginDomNode, renderOptions.fontInfo);
|
||||
|
||||
//if (this._renderIndicators) {
|
||||
for (let i = 0; i < result.heightInLines; i++) {
|
||||
const marginElement = document.createElement('div');
|
||||
marginElement.className = `delete-sign ${ThemeIcon.asClassName(diffRemoveIcon)}`;
|
||||
marginElement.setAttribute('style', `position:absolute;top:${i * modLineHeight}px;width:${renderOptions.lineDecorationsWidth}px;height:${modLineHeight}px;right:0;`);
|
||||
marginDomNode.appendChild(marginElement);
|
||||
}
|
||||
//}
|
||||
|
||||
let zoneId: string | undefined = undefined;
|
||||
alignmentViewZonesDisposables.add(
|
||||
new InlineDiffDeletedCodeMargin(
|
||||
() => assertIsDefined(zoneId),
|
||||
marginDomNode,
|
||||
this._modifiedEditor,
|
||||
a.diff,
|
||||
this._diffEditorWidget,
|
||||
result.viewLineCounts,
|
||||
this._originalEditor.getModel()!,
|
||||
this._contextMenuService,
|
||||
this._clipboardService,
|
||||
)
|
||||
);
|
||||
|
||||
for (let i = 0; i < result.viewLineCounts.length; i++) {
|
||||
const count = result.viewLineCounts[i];
|
||||
// Account for wrapped lines in the (collapsed) original editor (which doesn't wrap lines).
|
||||
if (count > 1) {
|
||||
origViewZones.push({
|
||||
afterLineNumber: a.originalRange.startLineNumber + i,
|
||||
domNode: createFakeLinesDiv(),
|
||||
heightInPx: (count - 1) * modLineHeight,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
modViewZones.push({
|
||||
afterLineNumber: a.modifiedRange.startLineNumber - 1,
|
||||
domNode: deletedCodeDomNode,
|
||||
heightInPx: result.heightInLines * modLineHeight,
|
||||
minWidthInPx: result.minWidthInPx,
|
||||
marginDomNode,
|
||||
setZoneId(id) { zoneId = id; },
|
||||
});
|
||||
}
|
||||
|
||||
const marginDomNode = document.createElement('div');
|
||||
marginDomNode.className = 'gutter-delete';
|
||||
|
||||
origViewZones.push({
|
||||
afterLineNumber: a.originalRange.endLineNumberExclusive - 1,
|
||||
domNode: createFakeLinesDiv(),
|
||||
heightInPx: a.modifiedHeightInPx,
|
||||
marginDomNode,
|
||||
});
|
||||
} else {
|
||||
const delta = a.modifiedHeightInPx - a.originalHeightInPx;
|
||||
if (delta > 0) {
|
||||
if (syncedMovedText?.lineRangeMapping.originalRange.contains(a.originalRange.endLineNumberExclusive - 1)) {
|
||||
@@ -123,10 +250,22 @@ export class ViewZoneAlignment extends Disposable {
|
||||
continue;
|
||||
}
|
||||
|
||||
function createViewZoneMarginArrow(): HTMLElement {
|
||||
const arrow = document.createElement('div');
|
||||
arrow.className = 'arrow-revert-change ' + ThemeIcon.asClassName(Codicon.arrowRight);
|
||||
return $('div', {}, arrow);
|
||||
}
|
||||
|
||||
let marginDomNode: HTMLElement | undefined = undefined;
|
||||
if (a.diff && a.diff.modifiedRange.isEmpty) {
|
||||
marginDomNode = createViewZoneMarginArrow();
|
||||
}
|
||||
|
||||
modViewZones.push({
|
||||
afterLineNumber: a.modifiedRange.endLineNumberExclusive - 1,
|
||||
domNode: createFakeLinesDiv(),
|
||||
heightInPx: -delta,
|
||||
marginDomNode,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -138,6 +277,7 @@ export class ViewZoneAlignment extends Disposable {
|
||||
// ignore unrelated alignments outside the synced moved text
|
||||
continue;
|
||||
}
|
||||
|
||||
const delta = a.modifiedHeightInPx - a.originalHeightInPx;
|
||||
if (delta > 0) {
|
||||
origViewZones.push({
|
||||
@@ -158,19 +298,35 @@ export class ViewZoneAlignment extends Disposable {
|
||||
});
|
||||
|
||||
this._register(autorunWithStore2('alignment viewzones', (reader) => {
|
||||
const scrollState = StableEditorScrollState.capture(this._modifiedEditor);
|
||||
|
||||
const alignmentViewZones_ = alignmentViewZones.read(reader);
|
||||
isChangingViewZones = true;
|
||||
this._originalEditor.changeViewZones((aOrig) => {
|
||||
for (const id of alignmentViewZoneIdsOrig) { aOrig.removeZone(id); }
|
||||
alignmentViewZoneIdsOrig.clear();
|
||||
for (const z of alignmentViewZones_.orig) { alignmentViewZoneIdsOrig.add(aOrig.addZone(z)); }
|
||||
for (const z of alignmentViewZones_.orig) {
|
||||
const id = aOrig.addZone(z);
|
||||
if (z.setZoneId) {
|
||||
z.setZoneId(id);
|
||||
}
|
||||
alignmentViewZoneIdsOrig.add(id);
|
||||
}
|
||||
});
|
||||
this._modifiedEditor.changeViewZones(aMod => {
|
||||
for (const id of alignmentViewZoneIdsMod) { aMod.removeZone(id); }
|
||||
alignmentViewZoneIdsMod.clear();
|
||||
for (const z of alignmentViewZones_.mod) { alignmentViewZoneIdsMod.add(aMod.addZone(z)); }
|
||||
for (const z of alignmentViewZones_.mod) {
|
||||
const id = aMod.addZone(z);
|
||||
if (z.setZoneId) {
|
||||
z.setZoneId(id);
|
||||
}
|
||||
alignmentViewZoneIdsMod.add(id);
|
||||
}
|
||||
});
|
||||
isChangingViewZones = false;
|
||||
|
||||
scrollState.restore(this._modifiedEditor);
|
||||
}));
|
||||
|
||||
this._originalScrollTop = observableFromEvent(this._originalEditor.onDidScrollChange, () => this._originalEditor.getScrollTop());
|
||||
@@ -187,7 +343,7 @@ export class ViewZoneAlignment extends Disposable {
|
||||
this._register(autorun('update scroll modified', (reader) => {
|
||||
const newScrollTopModified = this._originalScrollTop.read(reader)
|
||||
- (this._originalScrollOffsetAnimated.get() - this._modifiedScrollOffsetAnimated.read(reader))
|
||||
- (this._origExtraHeight.get() - this._modExtraHeight.read(reader));
|
||||
- (this._originalTopPadding.get() - this._modifiedTopPadding.read(reader));
|
||||
if (newScrollTopModified !== this._modifiedEditor.getScrollTop()) {
|
||||
this._modifiedEditor.setScrollTop(newScrollTopModified, ScrollType.Immediate);
|
||||
}
|
||||
@@ -196,7 +352,7 @@ export class ViewZoneAlignment extends Disposable {
|
||||
this._register(autorun('update scroll original', (reader) => {
|
||||
const newScrollTopOriginal = this._modifiedScrollTop.read(reader)
|
||||
- (this._modifiedScrollOffsetAnimated.get() - this._originalScrollOffsetAnimated.read(reader))
|
||||
- (this._modExtraHeight.get() - this._origExtraHeight.read(reader));
|
||||
- (this._modifiedTopPadding.get() - this._originalTopPadding.read(reader));
|
||||
if (newScrollTopOriginal !== this._originalEditor.getScrollTop()) {
|
||||
this._originalEditor.setScrollTop(newScrollTopOriginal, ScrollType.Immediate);
|
||||
}
|
||||
@@ -208,21 +364,21 @@ export class ViewZoneAlignment extends Disposable {
|
||||
|
||||
let deltaOrigToMod = 0;
|
||||
if (m) {
|
||||
const trueTopOriginal = this._originalEditor.getTopForLineNumber(m.lineRangeMapping.originalRange.startLineNumber, true) - this._origExtraHeight.get();
|
||||
const trueTopModified = this._modifiedEditor.getTopForLineNumber(m.lineRangeMapping.modifiedRange.startLineNumber, true) - this._modExtraHeight.get();
|
||||
const trueTopOriginal = this._originalEditor.getTopForLineNumber(m.lineRangeMapping.originalRange.startLineNumber, true) - this._originalTopPadding.get();
|
||||
const trueTopModified = this._modifiedEditor.getTopForLineNumber(m.lineRangeMapping.modifiedRange.startLineNumber, true) - this._modifiedTopPadding.get();
|
||||
deltaOrigToMod = trueTopModified - trueTopOriginal;
|
||||
}
|
||||
|
||||
if (deltaOrigToMod > 0) {
|
||||
this._modExtraHeight.set(0, undefined);
|
||||
this._origExtraHeight.set(deltaOrigToMod, undefined);
|
||||
this._modifiedTopPadding.set(0, undefined);
|
||||
this._originalTopPadding.set(deltaOrigToMod, undefined);
|
||||
} else if (deltaOrigToMod < 0) {
|
||||
this._modExtraHeight.set(-deltaOrigToMod, undefined);
|
||||
this._origExtraHeight.set(0, undefined);
|
||||
this._modifiedTopPadding.set(-deltaOrigToMod, undefined);
|
||||
this._originalTopPadding.set(0, undefined);
|
||||
} else {
|
||||
setTimeout(() => {
|
||||
this._modExtraHeight.set(0, undefined);
|
||||
this._origExtraHeight.set(0, undefined);
|
||||
this._modifiedTopPadding.set(0, undefined);
|
||||
this._originalTopPadding.set(0, undefined);
|
||||
}, 400);
|
||||
}
|
||||
|
||||
@@ -235,13 +391,24 @@ export class ViewZoneAlignment extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
interface IRangeAlignment {
|
||||
interface IViewZoneWithZoneId extends IViewZone {
|
||||
// Tells a view zone its id.
|
||||
setZoneId?(zoneId: string): void;
|
||||
}
|
||||
|
||||
interface ILineRangeAlignment {
|
||||
originalRange: LineRange;
|
||||
modifiedRange: LineRange;
|
||||
|
||||
// accounts for foreign viewzones and line wrapping
|
||||
originalHeightInPx: number;
|
||||
modifiedHeightInPx: number;
|
||||
|
||||
/**
|
||||
* If this range alignment is a direct result of a diff, then this is the diff's line mapping.
|
||||
* Only used for inline-view.
|
||||
*/
|
||||
diff?: LineRangeMapping;
|
||||
}
|
||||
|
||||
function computeRangeAlignment(
|
||||
@@ -250,14 +417,14 @@ function computeRangeAlignment(
|
||||
diffs: readonly DiffMapping[],
|
||||
originalEditorAlignmentViewZones: ReadonlySet<string>,
|
||||
modifiedEditorAlignmentViewZones: ReadonlySet<string>,
|
||||
): IRangeAlignment[] {
|
||||
): ILineRangeAlignment[] {
|
||||
const originalLineHeightOverrides = new ArrayQueue(getAdditionalLineHeights(originalEditor, originalEditorAlignmentViewZones));
|
||||
const modifiedLineHeightOverrides = new ArrayQueue(getAdditionalLineHeights(modifiedEditor, modifiedEditorAlignmentViewZones));
|
||||
|
||||
const origLineHeight = originalEditor.getOption(EditorOption.lineHeight);
|
||||
const modLineHeight = modifiedEditor.getOption(EditorOption.lineHeight);
|
||||
|
||||
const result: IRangeAlignment[] = [];
|
||||
const result: ILineRangeAlignment[] = [];
|
||||
|
||||
let lastOriginalLineNumber = 0;
|
||||
let lastModifiedLineNumber = 0;
|
||||
@@ -301,6 +468,7 @@ function computeRangeAlignment(
|
||||
modifiedRange: LineRange.ofLength(modNext!.lineNumber, 1),
|
||||
originalHeightInPx: origLineHeight + origNext!.heightInPx,
|
||||
modifiedHeightInPx: modLineHeight + modNext!.heightInPx,
|
||||
diff: undefined,
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -321,6 +489,7 @@ function computeRangeAlignment(
|
||||
modifiedRange: c.modifiedRange,
|
||||
originalHeightInPx: c.originalRange.length * origLineHeight + originalAdditionalHeight,
|
||||
modifiedHeightInPx: c.modifiedRange.length * modLineHeight + modifiedAdditionalHeight,
|
||||
diff: m.lineRangeMapping,
|
||||
});
|
||||
|
||||
lastOriginalLineNumber = c.originalRange.endLineNumberExclusive;
|
||||
|
||||
@@ -42,8 +42,9 @@ export class MovedBlocksLinesPart extends Disposable {
|
||||
const originalScrollTop = observableFromEvent(this._originalEditor.onDidScrollChange, () => this._originalEditor.getScrollTop());
|
||||
const modifiedScrollTop = observableFromEvent(this._modifiedEditor.onDidScrollChange, () => this._modifiedEditor.getScrollTop());
|
||||
|
||||
|
||||
this._register(autorun('update', (reader) => {
|
||||
element.replaceChildren();
|
||||
|
||||
const info = this._originalEditorLayoutInfo.read(reader);
|
||||
const info2 = this._modifiedEditorLayoutInfo.read(reader);
|
||||
if (!info || !info2) {
|
||||
@@ -56,8 +57,6 @@ export class MovedBlocksLinesPart extends Disposable {
|
||||
return;
|
||||
}
|
||||
|
||||
element.replaceChildren();
|
||||
|
||||
let idx = 0;
|
||||
for (const m of moves) {
|
||||
function computeLineStart(range: LineRange, editor: ICodeEditor) {
|
||||
|
||||
@@ -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 { createTrustedTypesPolicy } from 'vs/base/browser/trustedTypes';
|
||||
import { applyFontInfo } from 'vs/editor/browser/config/domFontInfo';
|
||||
import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
||||
import { EditorOption, EditorFontLigatures, FindComputedEditorOptionValueById } from 'vs/editor/common/config/editorOptions';
|
||||
import { FontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { StringBuilder } from 'vs/editor/common/core/stringBuilder';
|
||||
import { ModelLineProjectionData } from 'vs/editor/common/modelLineProjectionData';
|
||||
import { IViewLineTokens, LineTokens } from 'vs/editor/common/tokens/lineTokens';
|
||||
import { LineDecoration } from 'vs/editor/common/viewLayout/lineDecorations';
|
||||
import { renderViewLine, RenderLineInput } from 'vs/editor/common/viewLayout/viewLineRenderer';
|
||||
import { InlineDecoration, ViewLineRenderingData } from 'vs/editor/common/viewModel';
|
||||
|
||||
const ttPolicy = createTrustedTypesPolicy('diffEditorWidget2', { createHTML: value => value });
|
||||
|
||||
export function renderLines(source: LineSource, options: RenderOptions, decorations: InlineDecoration[], domNode: HTMLElement): RenderLinesResult {
|
||||
applyFontInfo(domNode, options.fontInfo);
|
||||
|
||||
const hasCharChanges = (decorations.length > 0);
|
||||
|
||||
const sb = new StringBuilder(10000);
|
||||
let maxCharsPerLine = 0;
|
||||
let renderedLineCount = 0;
|
||||
const viewLineCounts: number[] = [];
|
||||
for (let lineIndex = 0; lineIndex < source.lineTokens.length; lineIndex++) {
|
||||
const lineNumber = lineIndex + 1;
|
||||
const lineTokens = source.lineTokens[lineIndex];
|
||||
const lineBreakData = source.lineBreakData[lineIndex];
|
||||
const actualDecorations = LineDecoration.filter(decorations, lineNumber, 1, Number.MAX_SAFE_INTEGER);
|
||||
|
||||
if (lineBreakData) {
|
||||
let lastBreakOffset = 0;
|
||||
for (const breakOffset of lineBreakData.breakOffsets) {
|
||||
const viewLineTokens = lineTokens.sliceAndInflate(lastBreakOffset, breakOffset, 0);
|
||||
maxCharsPerLine = Math.max(maxCharsPerLine, renderOriginalLine(
|
||||
renderedLineCount,
|
||||
viewLineTokens,
|
||||
LineDecoration.extractWrapped(actualDecorations, lastBreakOffset, breakOffset),
|
||||
hasCharChanges,
|
||||
source.mightContainNonBasicASCII,
|
||||
source.mightContainRTL,
|
||||
options,
|
||||
sb,
|
||||
//marginDomNode
|
||||
));
|
||||
renderedLineCount++;
|
||||
lastBreakOffset = breakOffset;
|
||||
}
|
||||
viewLineCounts.push(lineBreakData.breakOffsets.length);
|
||||
|
||||
|
||||
/*
|
||||
const marginDomNode2 = document.createElement('div');
|
||||
marginDomNode2.className = 'gutter-delete';
|
||||
result.original.push({
|
||||
afterLineNumber: lineNumber,
|
||||
afterColumn: 0,
|
||||
heightInLines: lineBreakData.breakOffsets.length - 1,
|
||||
domNode: createFakeLinesDiv(),
|
||||
marginDomNode: marginDomNode2
|
||||
});
|
||||
*/
|
||||
} else {
|
||||
viewLineCounts.push(1);
|
||||
maxCharsPerLine = Math.max(maxCharsPerLine, renderOriginalLine(
|
||||
renderedLineCount,
|
||||
lineTokens,
|
||||
actualDecorations,
|
||||
hasCharChanges,
|
||||
source.mightContainNonBasicASCII,
|
||||
source.mightContainRTL,
|
||||
options,
|
||||
sb,
|
||||
));
|
||||
renderedLineCount++;
|
||||
}
|
||||
}
|
||||
maxCharsPerLine += options.scrollBeyondLastColumn;
|
||||
|
||||
const html = sb.build();
|
||||
const trustedhtml = ttPolicy ? ttPolicy.createHTML(html) : html;
|
||||
domNode.innerHTML = trustedhtml as string;
|
||||
const minWidthInPx = (maxCharsPerLine * options.typicalHalfwidthCharacterWidth);
|
||||
|
||||
return {
|
||||
heightInLines: renderedLineCount,
|
||||
minWidthInPx,
|
||||
viewLineCounts,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
export class LineSource {
|
||||
constructor(
|
||||
public readonly lineTokens: LineTokens[],
|
||||
public readonly lineBreakData: (ModelLineProjectionData | null)[],
|
||||
public readonly mightContainNonBasicASCII: boolean,
|
||||
public readonly mightContainRTL: boolean,
|
||||
) { }
|
||||
}
|
||||
|
||||
export class RenderOptions {
|
||||
public static fromEditor(editor: ICodeEditor): RenderOptions {
|
||||
|
||||
const modifiedEditorOptions = editor.getOptions();
|
||||
const fontInfo = modifiedEditorOptions.get(EditorOption.fontInfo);
|
||||
const layoutInfo = modifiedEditorOptions.get(EditorOption.layoutInfo);
|
||||
|
||||
return new RenderOptions(
|
||||
editor.getModel()?.getOptions().tabSize || 0,
|
||||
fontInfo,
|
||||
modifiedEditorOptions.get(EditorOption.disableMonospaceOptimizations),
|
||||
fontInfo.typicalHalfwidthCharacterWidth,
|
||||
modifiedEditorOptions.get(EditorOption.scrollBeyondLastColumn),
|
||||
|
||||
modifiedEditorOptions.get(EditorOption.lineHeight),
|
||||
|
||||
layoutInfo.decorationsWidth,
|
||||
modifiedEditorOptions.get(EditorOption.stopRenderingLineAfter),
|
||||
modifiedEditorOptions.get(EditorOption.renderWhitespace),
|
||||
modifiedEditorOptions.get(EditorOption.renderControlCharacters),
|
||||
modifiedEditorOptions.get(EditorOption.fontLigatures),
|
||||
);
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly tabSize: number,
|
||||
public readonly fontInfo: FontInfo,
|
||||
public readonly disableMonospaceOptimizations: boolean,
|
||||
public readonly typicalHalfwidthCharacterWidth: number,
|
||||
public readonly scrollBeyondLastColumn: number,
|
||||
public readonly lineHeight: number,
|
||||
public readonly lineDecorationsWidth: number,
|
||||
public readonly stopRenderingLineAfter: number,
|
||||
public readonly renderWhitespace: FindComputedEditorOptionValueById<EditorOption.renderWhitespace>,
|
||||
public readonly renderControlCharacters: boolean,
|
||||
public readonly fontLigatures: FindComputedEditorOptionValueById<EditorOption.fontLigatures>,
|
||||
) { }
|
||||
}
|
||||
|
||||
export interface RenderLinesResult {
|
||||
minWidthInPx: number;
|
||||
heightInLines: number;
|
||||
viewLineCounts: number[];
|
||||
}
|
||||
|
||||
function renderOriginalLine(
|
||||
viewLineIdx: number,
|
||||
lineTokens: IViewLineTokens,
|
||||
decorations: LineDecoration[],
|
||||
hasCharChanges: boolean,
|
||||
mightContainNonBasicASCII: boolean,
|
||||
mightContainRTL: boolean,
|
||||
options: RenderOptions,
|
||||
sb: StringBuilder,
|
||||
): number {
|
||||
|
||||
sb.appendString('<div class="view-line');
|
||||
if (!hasCharChanges) {
|
||||
// No char changes
|
||||
sb.appendString(' char-delete');
|
||||
}
|
||||
sb.appendString('" style="top:');
|
||||
sb.appendString(String(viewLineIdx * options.lineHeight));
|
||||
sb.appendString('px;width:1000000px;">');
|
||||
|
||||
const lineContent = lineTokens.getLineContent();
|
||||
const isBasicASCII = ViewLineRenderingData.isBasicASCII(lineContent, mightContainNonBasicASCII);
|
||||
const containsRTL = ViewLineRenderingData.containsRTL(lineContent, isBasicASCII, mightContainRTL);
|
||||
const output = renderViewLine(new RenderLineInput(
|
||||
(options.fontInfo.isMonospace && !options.disableMonospaceOptimizations),
|
||||
options.fontInfo.canUseHalfwidthRightwardsArrow,
|
||||
lineContent,
|
||||
false,
|
||||
isBasicASCII,
|
||||
containsRTL,
|
||||
0,
|
||||
lineTokens,
|
||||
decorations,
|
||||
options.tabSize,
|
||||
0,
|
||||
options.fontInfo.spaceWidth,
|
||||
options.fontInfo.middotWidth,
|
||||
options.fontInfo.wsmiddotWidth,
|
||||
options.stopRenderingLineAfter,
|
||||
options.renderWhitespace,
|
||||
options.renderControlCharacters,
|
||||
options.fontLigatures !== EditorFontLigatures.OFF,
|
||||
null // Send no selections, original line cannot be selected
|
||||
), sb);
|
||||
|
||||
sb.appendString('</div>');
|
||||
|
||||
return output.characterMapping.getHorizontalOffset(output.characterMapping.length);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,8 @@ export class UnchangedRangesFeature extends Disposable {
|
||||
const m = this._diffModel.get();
|
||||
transaction(tx => {
|
||||
for (const s of this._originalEditor.getSelections() || []) {
|
||||
m?.revealOriginalLine(s.getStartPosition().lineNumber, tx);
|
||||
m?.revealOriginalLine(s.getEndPosition().lineNumber, tx);
|
||||
m?.ensureOriginalLineIsVisible(s.getStartPosition().lineNumber, tx);
|
||||
m?.ensureOriginalLineIsVisible(s.getEndPosition().lineNumber, tx);
|
||||
}
|
||||
});
|
||||
}));
|
||||
@@ -38,8 +38,8 @@ export class UnchangedRangesFeature extends Disposable {
|
||||
const m = this._diffModel.get();
|
||||
transaction(tx => {
|
||||
for (const s of this._modifiedEditor.getSelections() || []) {
|
||||
m?.revealModifiedLine(s.getStartPosition().lineNumber, tx);
|
||||
m?.revealModifiedLine(s.getEndPosition().lineNumber, tx);
|
||||
m?.ensureModifiedLineIsVisible(s.getStartPosition().lineNumber, tx);
|
||||
m?.ensureModifiedLineIsVisible(s.getEndPosition().lineNumber, tx);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
@@ -20,6 +20,8 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
private diffAlgorithm: DiffAlgorithmName | IDocumentDiffProvider = 'advanced';
|
||||
private diffAlgorithmOnDidChangeSubscription: IDisposable | undefined = undefined;
|
||||
|
||||
private static readonly diffCache = new Map<string, { result: IDocumentDiff; context: string }>();
|
||||
|
||||
constructor(
|
||||
options: IWorkerBasedDocumentDiffProviderOptions,
|
||||
@IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService,
|
||||
@@ -58,6 +60,13 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
};
|
||||
}
|
||||
|
||||
const uriKey = JSON.stringify([original.uri.toString(), modified.uri.toString()]);
|
||||
const context = JSON.stringify([original.id, modified.id, original.getAlternativeVersionId(), modified.getAlternativeVersionId(), JSON.stringify(options)]);
|
||||
const c = WorkerBasedDocumentDiffProvider.diffCache.get(uriKey);
|
||||
if (c && c.context === context) {
|
||||
return c.result;
|
||||
}
|
||||
|
||||
const sw = StopWatch.create(true);
|
||||
const result = await this.editorWorkerService.computeDiff(original.uri, modified.uri, options, this.diffAlgorithm);
|
||||
const timeMs = sw.elapsed();
|
||||
@@ -81,6 +90,12 @@ export class WorkerBasedDocumentDiffProvider implements IDocumentDiffProvider, I
|
||||
throw new Error('no diff result available');
|
||||
}
|
||||
|
||||
// max 10 items in cache
|
||||
if (WorkerBasedDocumentDiffProvider.diffCache.size > 10) {
|
||||
WorkerBasedDocumentDiffProvider.diffCache.delete(WorkerBasedDocumentDiffProvider.diffCache.keys().next().value);
|
||||
}
|
||||
|
||||
WorkerBasedDocumentDiffProvider.diffCache.set(uriKey, { result, context });
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,4 +203,12 @@ export class LineRange {
|
||||
public toExclusiveRange(): Range {
|
||||
return new Range(this.startLineNumber, 1, this.endLineNumberExclusive, 1);
|
||||
}
|
||||
|
||||
public mapToLineArray<T>(f: (lineNumber: number) => T): T[] {
|
||||
const result: T[] = [];
|
||||
for (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) {
|
||||
result.push(f(lineNumber));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +102,10 @@ export class LineRangeMapping {
|
||||
public get changedLineCount() {
|
||||
return Math.max(this.originalRange.length, this.modifiedRange.length);
|
||||
}
|
||||
|
||||
public flip(): LineRangeMapping {
|
||||
return new LineRangeMapping(this.modifiedRange, this.originalRange, this.innerChanges?.map(c => c.flip()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -130,6 +134,10 @@ export class RangeMapping {
|
||||
public toString(): string {
|
||||
return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;
|
||||
}
|
||||
|
||||
public flip(): RangeMapping {
|
||||
return new RangeMapping(this.modifiedRange, this.originalRange);
|
||||
}
|
||||
}
|
||||
|
||||
export class SimpleLineRangeMapping {
|
||||
@@ -142,6 +150,10 @@ export class SimpleLineRangeMapping {
|
||||
public toString(): string {
|
||||
return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`;
|
||||
}
|
||||
|
||||
public flip(): SimpleLineRangeMapping {
|
||||
return new SimpleLineRangeMapping(this.modifiedRange, this.originalRange);
|
||||
}
|
||||
}
|
||||
|
||||
export class MovedText {
|
||||
@@ -161,4 +173,8 @@ export class MovedText {
|
||||
this.lineRangeMapping = lineRangeMapping;
|
||||
this.changes = changes;
|
||||
}
|
||||
|
||||
public flip(): MovedText {
|
||||
return new MovedText(this.lineRangeMapping.flip(), this.changes.map(c => c.flip()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,7 @@ export interface IDiffComputationResult {
|
||||
|
||||
/**
|
||||
* The changes as (legacy) line change array.
|
||||
* @deprecated Use `changes2` instead.
|
||||
*/
|
||||
changes: ILineChange[];
|
||||
|
||||
|
||||
@@ -104,6 +104,12 @@ export interface IDiffEditorModel {
|
||||
modified: ITextModel;
|
||||
}
|
||||
|
||||
export interface IDiffEditorViewModel {
|
||||
readonly model: IDiffEditorModel;
|
||||
|
||||
waitForDiff(): Promise<void>;
|
||||
}
|
||||
|
||||
/**
|
||||
* An event describing that an editor has had its model reset (i.e. `editor.setModel()`).
|
||||
*/
|
||||
@@ -153,7 +159,7 @@ export interface IEditorAction {
|
||||
run(args?: unknown): Promise<void>;
|
||||
}
|
||||
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel;
|
||||
export type IEditorModel = ITextModel | IDiffEditorModel | IDiffEditorViewModel;
|
||||
|
||||
/**
|
||||
* A (serializable) state of the cursors.
|
||||
|
||||
@@ -97,6 +97,10 @@ export class CodeActionController extends Disposable implements IEditorContribut
|
||||
return this.showCodeActionList(actions, at, { includeDisabledActions: false, fromLightbulb: false });
|
||||
}
|
||||
|
||||
public hideCodeActions(): void {
|
||||
this._actionWidgetService.hide();
|
||||
}
|
||||
|
||||
public manualTriggerAtCurrentPosition(
|
||||
notAvailableMessage: string,
|
||||
triggerAction: CodeActionTriggerSource,
|
||||
@@ -126,6 +130,10 @@ export class CodeActionController extends Disposable implements IEditorContribut
|
||||
}
|
||||
}
|
||||
|
||||
public hideLightBulbWidget(): void {
|
||||
this._lightBulbWidget.rawValue?.hide();
|
||||
}
|
||||
|
||||
private async update(newState: CodeActionsState.State): Promise<void> {
|
||||
if (newState.type !== CodeActionsState.Type.Triggered) {
|
||||
this._lightBulbWidget.rawValue?.hide();
|
||||
|
||||
@@ -332,6 +332,7 @@ export class SuggestController implements IEditorContribution {
|
||||
// keep item in memory
|
||||
this._memoryService.memorize(model, this.editor.getPosition(), item);
|
||||
|
||||
const isResolved = item.isResolved;
|
||||
|
||||
if (Array.isArray(item.completion.additionalTextEdits)) {
|
||||
|
||||
@@ -346,7 +347,7 @@ export class SuggestController implements IEditorContribution {
|
||||
);
|
||||
scrollState.restoreRelativeVerticalPositionOfCursor(this.editor);
|
||||
|
||||
} else if (!item.isResolved) {
|
||||
} else if (!isResolved) {
|
||||
// async additional edits
|
||||
const sw = new StopWatch(true);
|
||||
let position: IPosition | undefined;
|
||||
@@ -378,7 +379,7 @@ export class SuggestController implements IEditorContribution {
|
||||
|
||||
tasks.push(item.resolve(cts.token).then(() => {
|
||||
if (!item.completion.additionalTextEdits || cts.token.isCancellationRequested) {
|
||||
return false;
|
||||
return undefined;
|
||||
}
|
||||
if (position && item.completion.additionalTextEdits.some(edit => Position.isBefore(position!, Range.getStartPosition(edit.range)))) {
|
||||
return false;
|
||||
@@ -398,6 +399,20 @@ export class SuggestController implements IEditorContribution {
|
||||
return true;
|
||||
}).then(applied => {
|
||||
this._logService.trace('[suggest] async resolving of edits DONE (ms, applied?)', sw.elapsed(), applied);
|
||||
type AsyncSuggestEdits = { providerId: string; applied: boolean };
|
||||
type AsyncSuggestEditsClassification = {
|
||||
owner: 'jrieken';
|
||||
comment: 'Information about async additional text edits';
|
||||
providerId: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Provider of the completions item' };
|
||||
applied: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If async additional text edits could be applied' };
|
||||
};
|
||||
if (typeof applied === 'boolean') {
|
||||
this._telemetryService.publicLog2<AsyncSuggestEdits, AsyncSuggestEditsClassification>('suggest.asyncAdditionalEdits', {
|
||||
providerId: item.extensionId?.value ?? 'unknown',
|
||||
applied
|
||||
});
|
||||
}
|
||||
}).finally(() => {
|
||||
docListener.dispose();
|
||||
typeListener.dispose();
|
||||
}));
|
||||
@@ -467,7 +482,7 @@ export class SuggestController implements IEditorContribution {
|
||||
|
||||
// clear only now - after all tasks are done
|
||||
Promise.all(tasks).finally(() => {
|
||||
this._reportSuggestionAcceptedTelemetry(item, model, event);
|
||||
this._reportSuggestionAcceptedTelemetry(item, model, event, isResolved);
|
||||
|
||||
this.model.clear();
|
||||
cts.dispose();
|
||||
@@ -475,12 +490,12 @@ export class SuggestController implements IEditorContribution {
|
||||
}
|
||||
|
||||
private _telemetryGate: number = 0;
|
||||
private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, acceptedSuggestion: ISelectedSuggestion) {
|
||||
private _reportSuggestionAcceptedTelemetry(item: CompletionItem, model: ITextModel, acceptedSuggestion: ISelectedSuggestion, itemResolved: boolean) {
|
||||
if (this._telemetryGate++ % 100 !== 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
type AcceptedSuggestion = { providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number };
|
||||
type AcceptedSuggestion = { providerId: string; fileExtension: string; languageId: string; basenameHash: string; kind: number; itemResolved: boolean };
|
||||
type AcceptedSuggestionClassification = {
|
||||
owner: 'jrieken';
|
||||
comment: 'Information accepting completion items';
|
||||
@@ -488,7 +503,8 @@ export class SuggestController implements IEditorContribution {
|
||||
basenameHash: { classification: 'PublicNonPersonalData'; purpose: 'FeatureInsight'; comment: 'Hash of the basename of the file into which the completion was inserted' };
|
||||
fileExtension: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'File extension of the file into which the completion was inserted' };
|
||||
languageId: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'Language type of the file into which the completion was inserted' };
|
||||
kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; comment: 'The completion item kind' };
|
||||
kind: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'The completion item kind' };
|
||||
itemResolved: { classification: 'SystemMetaData'; purpose: 'FeatureInsight'; isMeasurement: true; comment: 'If the item was inserted before resolving was done' };
|
||||
};
|
||||
// _debugDisplayName looks like `vscode.css-language-features(/-:)`, where the last bit is the trigger chars
|
||||
// normalize it to just the extension ID and lowercase
|
||||
@@ -499,6 +515,7 @@ export class SuggestController implements IEditorContribution {
|
||||
basenameHash: hash(basename(model.uri)).toString(16),
|
||||
languageId: model.getLanguageId(),
|
||||
fileExtension: extname(model.uri),
|
||||
itemResolved
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -121,7 +121,12 @@ function doCreateTest(description: string, inputStr: string, expectedStr: string
|
||||
}
|
||||
};
|
||||
|
||||
const handler = new TextAreaInput(textAreaInputHost, new TextAreaWrapper(input), platform.OS, browser);
|
||||
const handler = new TextAreaInput(textAreaInputHost, new TextAreaWrapper(input), platform.OS, {
|
||||
isAndroid: browser.isAndroid,
|
||||
isFirefox: browser.isFirefox,
|
||||
isChrome: browser.isChrome,
|
||||
isSafari: browser.isSafari,
|
||||
});
|
||||
|
||||
const output = document.createElement('pre');
|
||||
output.className = 'output';
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user