Merge branch 'main' into tyriar/183423

This commit is contained in:
Daniel Imms
2023-06-14 10:43:14 -07:00
committed by GitHub
176 changed files with 4932 additions and 1888 deletions
+1 -1
View File
@@ -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
View File
@@ -1 +1 @@
2023-03-31T12:39:03.753Z
2023-06-12T12:55:48.130Z
+2
View File
@@ -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
+14 -1
View File
@@ -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
+14 -1
View File
@@ -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'))
+2 -2
View File
@@ -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
+34
View File
@@ -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
View File
@@ -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
+1
View File
@@ -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
+8 -7
View File
@@ -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;
});
}
+2 -2
View File
@@ -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}`;
+2 -2
View File
@@ -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
View File
File diff suppressed because one or more lines are too long
+18 -23
View File
@@ -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 {
+136
View File
File diff suppressed because one or more lines are too long
+147
View File
@@ -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);
}
}));
}
-48
View File
@@ -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
-47
View File
@@ -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}`));
}
}));
}
-84
View File
@@ -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
-95
View File
@@ -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;
}
}
+4
View File
@@ -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);
+20
View File
@@ -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
+26
View File
@@ -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;
}
File diff suppressed because one or more lines are too long
+5 -7
View File
@@ -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=
+4 -6
View File
@@ -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
-2
View File
@@ -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)',
+4
View File
@@ -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"
}
}
+12
View File
@@ -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
View File
@@ -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") {
+23 -4
View File
@@ -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;
});
+91
View File
@@ -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));
}
};
+1 -1
View File
@@ -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",
+24 -12
View File
@@ -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);
}
}
+2 -2
View File
@@ -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
View File
@@ -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.');
-70
View File
@@ -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();
}
}
+8 -41
View File
@@ -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);
+4 -4
View File
@@ -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);
+9 -37
View File
@@ -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);
+8 -35
View File
@@ -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);
+1 -1
View File
@@ -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'));
}
});
}
+12 -37
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
}
}
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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[]>;
}
}
-9
View File
@@ -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;
}
+25 -7
View File
@@ -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);
}
}
+1
View File
@@ -74,6 +74,7 @@ export class ErrorHandler {
export const errorHandler = new ErrorHandler();
/** @skipMangle */
export function setUnexpectedErrorHandler(newUnexpectedErrorHandler: (e: any) => void): void {
errorHandler.setUnexpectedErrorHandler(newUnexpectedErrorHandler);
}
+14 -2
View File
@@ -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 {
+2 -2
View File
@@ -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> {
+2
View File
@@ -48,6 +48,8 @@ else {
* environments.
*
* Note: in web, this property is hardcoded to be `/`.
*
* @skipMangle
*/
export const cwd = safeProcess.cwd;
+1 -1
View File
@@ -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);
+5 -8
View File
@@ -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() {
+5
View File
@@ -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
View File
@@ -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
};
}
+1 -1
View File
@@ -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
+2
View File
@@ -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);
+3 -20
View File
@@ -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;
}
+8
View File
@@ -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[];
+7 -1
View File
@@ -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