Merge remote-tracking branch 'origin/master' into tyriar/puppeteer

This commit is contained in:
Daniel Imms 2019-07-15 10:34:58 -07:00
commit f784f5fd7f
173 changed files with 3112 additions and 1763 deletions

View file

@ -81,7 +81,7 @@
hot-exit: [],
html: [],
install-update: [],
integrated-terminal: [ Tyriar ],
integrated-terminal: [],
integration-test: [],
intellisense-config: [],
issue-reporter: [ RMacfarlane ],

4
.gitignore vendored
View file

@ -18,9 +18,11 @@ out-vscode-min/
out-vscode-reh/
out-vscode-reh-min/
out-vscode-reh-pkg/
out-vscode-reh-web/
out-vscode-reh-web-min/
out-vscode-reh-web-pkg/
out-vscode-web/
out-vscode-web-min/
out-vscode-web-pkg/
src/vs/server
resources/server
build/node_modules

View file

@ -1 +1 @@
1
2019-07-11T05:47:05.444Z

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
@ -89,9 +89,7 @@ steps:
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-reh-darwin-min-ci
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-web-darwin-min-ci
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
yarn gulp upload-vscode-sourcemaps
yarn gulp vscode-reh-web-darwin-min-ci
displayName: Build
- script: |

View file

@ -30,7 +30,7 @@ node build/azure-pipelines/common/publish.js \
../vscode-server-darwin.zip
# publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS"
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS"
# upload configuration
yarn gulp upload-vscode-configuration

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
@ -34,8 +34,6 @@ steps:
- script: |
set -e
export npm_config_arch="$(VSCODE_ARCH)"
cat << EOF > ~/.netrc
machine github.com
login vscode
@ -86,22 +84,22 @@ steps:
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-linux-$VSCODE_ARCH-min-ci
yarn gulp vscode-linux-x64-min-ci
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-reh-linux-$VSCODE_ARCH-min-ci
yarn gulp vscode-reh-linux-x64-min-ci
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-web-linux-$VSCODE_ARCH-min-ci
yarn gulp vscode-reh-web-linux-x64-min-ci
displayName: Build
- script: |
set -e
yarn gulp "electron-$(VSCODE_ARCH)"
yarn gulp "electron-x64"
# xvfb seems to be crashing often, let's make sure it's always up
service xvfb start
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64"
displayName: Run unit tests
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
@ -117,7 +115,7 @@ steps:
- task: PublishPipelineArtifact@0
displayName: 'Publish Pipeline Artifact'
inputs:
artifactName: snap-$(VSCODE_ARCH)
artifactName: snap-x64
targetPath: .build/linux/snap-tarball
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0

View file

@ -4,7 +4,7 @@ REPO="$(pwd)"
ROOT="$REPO/.."
# Publish tarball
PLATFORM_LINUX="linux-$VSCODE_ARCH"
PLATFORM_LINUX="linux-x64"
BUILDNAME="VSCode-$PLATFORM_LINUX"
BUILD="$ROOT/$BUILDNAME"
BUILD_VERSION="$(date +%s)"
@ -19,24 +19,22 @@ rm -rf $ROOT/code-*.tar.*
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
# Publish Remote Extension Host
if [[ "$VSCODE_ARCH" != "ia32" ]]; then
LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX"
SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX"
SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz"
SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME"
LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX"
SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX"
SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz"
SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME"
rm -rf $ROOT/vscode-server-*.tar.*
(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME)
rm -rf $ROOT/vscode-server-*.tar.*
(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME)
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH"
fi
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH"
# Publish hockeyapp symbols
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64"
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64"
# Publish DEB
yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb"
PLATFORM_DEB="linux-deb-$VSCODE_ARCH"
yarn gulp "vscode-linux-x64-build-deb"
PLATFORM_DEB="linux-deb-x64"
DEB_ARCH="amd64"
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
@ -44,8 +42,8 @@ DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
# Publish RPM
yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm"
PLATFORM_RPM="linux-rpm-$VSCODE_ARCH"
yarn gulp "vscode-linux-x64-build-rpm"
PLATFORM_RPM="linux-rpm-x64"
RPM_ARCH="x86_64"
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
@ -53,10 +51,10 @@ RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
# Publish Snap
yarn gulp "vscode-linux-$VSCODE_ARCH-prepare-snap"
yarn gulp "vscode-linux-x64-prepare-snap"
# Pack snap tarball artifact, in order to preserve file perms
mkdir -p $REPO/.build/linux/snap-tarball
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz"
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz"
rm -rf $SNAP_TARBALL_PATH
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)

View file

@ -16,7 +16,7 @@ steps:
- task: DownloadPipelineArtifact@0
displayName: 'Download Pipeline Artifact'
inputs:
artifactName: snap-$(VSCODE_ARCH)
artifactName: snap-x64
targetPath: .build/linux/snap-tarball
- script: |
@ -31,14 +31,13 @@ steps:
# Define variables
REPO="$(pwd)"
ARCH="$(VSCODE_ARCH)"
SNAP_ROOT="$REPO/.build/linux/snap/$ARCH"
SNAP_ROOT="$REPO/.build/linux/snap/x64"
# Install build dependencies
(cd build && yarn)
# Unpack snap tarball artifact, in order to preserve file perms
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$ARCH.tar.gz"
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz"
(cd .build/linux && tar -xzf $SNAP_TARBALL_PATH)
# Create snap package
@ -52,4 +51,4 @@ steps:
# Publish snap package
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"

View file

@ -10,15 +10,12 @@ jobs:
- job: Compile
pool:
vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: vscode-x64
steps:
- template: product-compile.yml
- job: Windows
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true'))
timeoutInMinutes: 120
pool:
vmImage: VS2017-Win2016
variables:
@ -30,7 +27,6 @@ jobs:
- job: Windows32
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true'))
timeoutInMinutes: 120
pool:
vmImage: VS2017-Win2016
variables:
@ -42,11 +38,8 @@ jobs:
- job: Linux
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: vscode-x64
dependsOn:
- Compile
@ -55,11 +48,8 @@ jobs:
- job: LinuxSnap
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: snapcraft
dependsOn: Linux
steps:
@ -67,7 +57,6 @@ jobs:
- job: LinuxArmhf
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'
variables:
@ -79,7 +68,6 @@ jobs:
- job: LinuxAlpine
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool:
vmImage: 'Ubuntu-16.04'
variables:
@ -89,9 +77,19 @@ jobs:
steps:
- template: linux/product-build-linux-multiarch.yml
- job: LinuxWeb
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WEB'], 'true'))
pool:
vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
dependsOn:
- Compile
steps:
- template: web/product-build-web.yml
- job: macOS
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true'))
timeoutInMinutes: 120
pool:
vmImage: macOS 10.13
dependsOn:

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
@ -31,8 +31,6 @@ steps:
- script: |
set -e
export npm_config_arch="$(VSCODE_ARCH)"
cat << EOF > ~/.netrc
machine github.com
login vscode
@ -105,14 +103,21 @@ steps:
yarn gulp compile-extensions-build
yarn gulp minify-vscode
yarn gulp minify-vscode-reh
yarn gulp minify-vscode-web
yarn gulp minify-vscode-reh-web
displayName: Compile
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- script: |
set -e
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
node build/azure-pipelines/upload-sourcemaps
displayName: Upload sourcemaps
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'

View file

@ -0,0 +1,39 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const path = require('path');
const es = require('event-stream');
const azure = require('gulp-azure-storage');
const vfs = require('vinyl-fs');
const util = require('../lib/util');
const root = path.dirname(path.dirname(__dirname));
const commit = util.getVersion(root);
function main() {
const vs = vfs.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only
.pipe(es.mapSync(f => {
f.path = `${f.base}/core/${f.relative}`;
return f;
}));
const extensionsOut = vfs.src(['.build/extensions/**/*.js.map', '!**/node_modules/**'], { base: '.build' });
return es.merge(vs, extensionsOut)
.pipe(es.through(function (data) {
// debug
console.log('Uploading Sourcemap', data.relative);
this.emit('data', data);
}))
.pipe(azure.upload({
account: process.env.AZURE_STORAGE_ACCOUNT,
key: process.env.AZURE_STORAGE_ACCESS_KEY,
container: 'sourcemaps',
prefix: commit + '/'
}));
}
main();

View file

@ -0,0 +1,96 @@
steps:
- script: |
mkdir -p .build
echo -n $BUILD_SOURCEVERSION > .build/commit
displayName: Prepare cache flag
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
- script: |
set -e
exit 1
displayName: Check RestoreCache
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
- task: NodeTool@0
inputs:
versionSpec: "10.15.1"
- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2
inputs:
versionSpec: "1.10.1"
- task: AzureKeyVault@1
displayName: 'Azure Key Vault: Get Secrets'
inputs:
azureSubscription: 'vscode-builds-subscription'
KeyVaultName: vscode
- script: |
set -e
cat << EOF > ~/.netrc
machine github.com
login vscode
password $(github-distro-mixin-password)
EOF
git config user.email "vscode@microsoft.com"
git config user.name "VSCode"
displayName: Prepare tooling
- script: |
set -e
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
git fetch distro
git merge $(node -p "require('./package.json').distro")
displayName: Merge distro
# - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
# inputs:
# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
# targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
# vstsFeed: 'npm-vscode'
- script: |
set -e
CHILD_CONCURRENCY=1 yarn --frozen-lockfile
displayName: Install dependencies
# condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
# - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
# inputs:
# keyfile: 'build/.cachesalt, .yarnrc, remote/.yarnrc, **/yarn.lock, !**/node_modules/**/yarn.lock, !**/.*/**/yarn.lock'
# targetfolder: '**/node_modules, !**/node_modules/**/node_modules'
# vstsFeed: 'npm-vscode'
# condition: and(succeeded(), ne(variables['CacheRestored'], 'true'))
# - script: |
# set -e
# yarn postinstall
# displayName: Run postinstall scripts
# condition: and(succeeded(), eq(variables['CacheRestored'], 'true'))
- script: |
set -e
node build/azure-pipelines/mixin
displayName: Mix in quality
- script: |
set -e
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
yarn gulp vscode-web-min-ci
displayName: Build
- script: |
set -e
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
./build/azure-pipelines/web/publish.sh
displayName: Publish

View file

@ -0,0 +1,15 @@
#!/usr/bin/env bash
set -e
REPO="$(pwd)"
ROOT="$REPO/.."
# Publish Web Client
WEB_BUILD_NAME="vscode-web"
WEB_TARBALL_FILENAME="vscode-web.tar.gz"
WEB_TARBALL_PATH="$ROOT/$WEB_TARBALL_FILENAME"
rm -rf $ROOT/vscode-web.tar.*
(cd $ROOT && tar --owner=0 --group=0 -czf $WEB_TARBALL_PATH $WEB_BUILD_NAME)
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "web-standalone" archive-unsigned "$WEB_TARBALL_FILENAME" "$VERSION" true "$WEB_TARBALL_PATH"

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs:
keyfile: '.build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode'
platformIndependent: true
alias: 'Compilation'
@ -98,7 +98,7 @@ steps:
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" }
exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" }
exec { yarn gulp "vscode-web-win32-$env:VSCODE_ARCH-min-ci" }
exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" }
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }
displayName: Build

View file

@ -43,11 +43,11 @@ gulp.task('vscode-reh-linux-x64-min', noop);
gulp.task('vscode-reh-linux-armhf-min', noop);
gulp.task('vscode-reh-linux-alpine-min', noop);
gulp.task('vscode-web-win32-ia32-min', noop);
gulp.task('vscode-web-win32-x64-min', noop);
gulp.task('vscode-web-darwin-min', noop);
gulp.task('vscode-web-linux-x64-min', noop);
gulp.task('vscode-web-linux-alpine-min', noop);
gulp.task('vscode-reh-web-win32-ia32-min', noop);
gulp.task('vscode-reh-web-win32-x64-min', noop);
gulp.task('vscode-reh-web-darwin-min', noop);
gulp.task('vscode-reh-web-linux-x64-min', noop);
gulp.task('vscode-reh-web-linux-alpine-min', noop);
function getNodeVersion() {
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');

View file

@ -63,7 +63,7 @@ const vscodeResources = [
'out-build/bootstrap-amd.js',
'out-build/bootstrap-window.js',
'out-build/paths.js',
'out-build/vs/**/*.{svg,png,cur,html}',
'out-build/vs/**/*.{svg,png,html}',
'!out-build/vs/code/browser/**/*.html',
'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/languagePacks.js',
@ -86,12 +86,6 @@ const vscodeResources = [
'!**/test/**'
];
const BUNDLED_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
util.rimraf('out-vscode'),
common.optimizeTask({
@ -99,7 +93,6 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
entryPoints: vscodeEntryPoints,
resources: vscodeResources,
loaderConfig: common.loaderConfig(nodeModules),
header: BUNDLED_FILE_HEADER,
out: 'out-vscode',
bundleInfo: undefined
})
@ -265,16 +258,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const src = gulp.src(out + '/**', { base: '.' })
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); }))
.pipe(util.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
const root = path.resolve(path.join(__dirname, '..'));
.pipe(util.setExecutableBit(['**/*.sh']));
const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true });
const sources = es.merge(src, extensions);
const sources = es.merge(src, extensions)
.pipe(filter(['**', '!**/*.js.map'], { dot: true }));
let version = packageJson.version;
// @ts-ignore JSON checking: quality is optional
const quality = product.quality;
if (quality && quality !== 'stable') {
@ -309,6 +300,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true });
const root = path.resolve(path.join(__dirname, '..'));
const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]));
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true })
@ -535,32 +527,6 @@ gulp.task('vscode-translations-import', function () {
}));
});
// Sourcemaps
gulp.task('upload-vscode-sourcemaps', () => {
const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only
.pipe(es.mapSync(f => {
f.path = `${f.base}/core/${f.relative}`;
return f;
}));
const extensionsOut = gulp.src(['extensions/**/out/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
const extensionsDist = gulp.src(['extensions/**/dist/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
return es.merge(vs, extensionsOut, extensionsDist)
.pipe(es.through(function (data) {
// debug
console.log('Uploading Sourcemap', data.relative);
this.emit('data', data);
}))
.pipe(azure.upload({
account: process.env.AZURE_STORAGE_ACCOUNT,
key: process.env.AZURE_STORAGE_ACCESS_KEY,
container: 'sourcemaps',
prefix: commit + '/'
}));
});
// This task is only run for the MacOS build
const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => {
return new Promise((resolve, reject) => {

View file

@ -0,0 +1,151 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
'use strict';
const gulp = require('gulp');
const path = require('path');
const es = require('event-stream');
const util = require('./lib/util');
const task = require('./lib/task');
const common = require('./lib/optimize');
const product = require('../product.json');
const rename = require('gulp-rename');
const filter = require('gulp-filter');
const json = require('gulp-json-editor');
const _ = require('underscore');
const deps = require('./dependencies');
const vfs = require('vinyl-fs');
const packageJson = require('../package.json');
const { compileBuildTask } = require('./gulpfile.compile');
const REPO_ROOT = path.dirname(__dirname);
const commit = util.getVersion(REPO_ROOT);
const BUILD_ROOT = path.dirname(REPO_ROOT);
const WEB_FOLDER = path.join(REPO_ROOT, 'remote', 'web');
const productionDependencies = deps.getProductionDependencies(WEB_FOLDER);
const nodeModules = Object.keys(product.dependencies || {})
.concat(_.uniq(productionDependencies.map(d => d.name)));
const vscodeWebResources = [
// Workbench
'out-build/vs/{base,platform,editor,workbench}/**/*.{svg,png,html}',
'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
'out-build/vs/**/markdown.css',
// Webview
'out-build/vs/workbench/contrib/webview/browser/pre/*.js',
// Excludes
'!out-build/vs/**/{node,electron-browser,electron-main}/**',
'!out-build/vs/editor/standalone/**',
'!out-build/vs/workbench/**/*-tb.png',
'!**/test/**'
];
const buildfile = require('../src/buildfile');
const vscodeWebEntryPoints = [
buildfile.workbenchWeb,
buildfile.serviceWorker,
buildfile.keyboardMaps,
buildfile.base
];
const optimizeVSCodeWebTask = task.define('optimize-vscode-web', task.series(
util.rimraf('out-vscode-web'),
common.optimizeTask({
src: 'out-build',
entryPoints: _.flatten(vscodeWebEntryPoints),
otherSources: [],
resources: vscodeWebResources,
loaderConfig: common.loaderConfig(nodeModules),
out: 'out-vscode-web',
bundleInfo: undefined
})
));
const minifyVSCodeWebTask = task.define('minify-vscode-web', task.series(
optimizeVSCodeWebTask,
util.rimraf('out-vscode-web-min'),
common.minifyTask('out-vscode-web', `https://ticino.blob.core.windows.net/sourcemaps/${commit}/core`)
));
gulp.task(minifyVSCodeWebTask);
function packageTask(sourceFolderName, destinationFolderName) {
const destination = path.join(BUILD_ROOT, destinationFolderName);
return () => {
const src = gulp.src(sourceFolderName + '/**', { base: '.' })
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + sourceFolderName), 'out'); }))
.pipe(filter(['**', '!**/*.js.map']));
const sources = es.merge(src);
let version = packageJson.version;
const quality = product.quality;
if (quality && quality !== 'stable') {
version += '-' + quality;
}
const name = product.nameShort;
const packageJsonStream = gulp.src(['remote/web/package.json'], { base: 'remote/web' })
.pipe(json({ name, version }));
const date = new Date().toISOString();
const productJsonStream = gulp.src(['product.json'], { base: '.' })
.pipe(json({ commit, date }));
const license = gulp.src(['remote/LICENSE'], { base: 'remote' });
const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(REPO_ROOT, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`, `!${d}/.bin/**`]));
const deps = gulp.src(dependenciesSrc, { base: 'remote/web', dot: true })
.pipe(filter(['**', '!**/package-lock.json']))
.pipe(util.cleanNodeModules(path.join(__dirname, '.nativeignore')));
const favicon = gulp.src('resources/server/favicon.ico', { base: 'resources/server' });
let all = es.merge(
packageJsonStream,
productJsonStream,
license,
sources,
deps,
favicon
);
let result = all
.pipe(util.skipDirectories())
.pipe(util.fixWin32DirectoryPermissions());
return result.pipe(vfs.dest(destination));
};
}
const dashed = (str) => (str ? `-${str}` : ``);
['', 'min'].forEach(minified => {
const sourceFolderName = `out-vscode-web${dashed(minified)}`;
const destinationFolderName = `vscode-web`;
const vscodeWebTaskCI = task.define(`vscode-web${dashed(minified)}-ci`, task.series(
minified ? minifyVSCodeWebTask : optimizeVSCodeWebTask,
util.rimraf(path.join(BUILD_ROOT, destinationFolderName)),
packageTask(sourceFolderName, destinationFolderName)
));
gulp.task(vscodeWebTaskCI);
const vscodeWebTask = task.define(`vscode-web${dashed(minified)}`, task.series(
compileBuildTask,
vscodeWebTaskCI
));
gulp.task(vscodeWebTask);
});

View file

@ -111,12 +111,6 @@ function fromLocalWebpack(extensionPath) {
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8');
if (/\.js\.map$/.test(data.path)) {
if (!fs.existsSync(path.dirname(data.path))) {
fs.mkdirSync(path.dirname(data.path));
}
fs.writeFileSync(data.path, data.contents);
}
this.emit('data', data);
}));
});
@ -195,20 +189,21 @@ function packageLocalExtensionsStream() {
})
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name));
return es.merge(gulp.src('extensions/node_modules/**', { base: '.' }), ...localExtensionDescriptions.map(extension => {
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
const localExtensions = localExtensionDescriptions.map(extension => {
return fromLocal(extension.path)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
}))
.pipe(util2.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
});
return es.merge(nodeModules, ...localExtensions)
.pipe(util2.setExecutableBit(['**/*.sh']));
}
exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
function packageMarketplaceExtensionsStream() {
return es.merge(builtInExtensions.map(extension => {
const extensions = builtInExtensions.map(extension => {
return fromMarketplace(extension.name, extension.version, extension.metadata)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
}))
.pipe(util2.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
});
return es.merge(extensions)
.pipe(util2.setExecutableBit(['**/*.sh']));
}
exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;

View file

@ -130,12 +130,6 @@ function fromLocalWebpack(extensionPath: string): Stream {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8');
if (/\.js\.map$/.test(data.path)) {
if (!fs.existsSync(path.dirname(data.path))) {
fs.mkdirSync(path.dirname(data.path));
}
fs.writeFileSync(data.path, data.contents);
}
this.emit('data', data);
}));
});
@ -237,22 +231,22 @@ export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream {
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name));
return es.merge(
gulp.src('extensions/node_modules/**', { base: '.' }),
...localExtensionDescriptions.map(extension => {
return fromLocal(extension.path)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
})
)
.pipe(util2.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
const localExtensions = localExtensionDescriptions.map(extension => {
return fromLocal(extension.path)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
});
return es.merge(nodeModules, ...localExtensions)
.pipe(util2.setExecutableBit(['**/*.sh']));
}
export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream {
return es.merge(builtInExtensions.map(extension => {
const extensions = builtInExtensions.map(extension => {
return fromMarketplace(extension.name, extension.version, extension.metadata)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
}))
.pipe(util2.setExecutableBit(['**/*.sh']))
.pipe(filter(['**', '!**/*.js.map']));
});
return es.merge(extensions)
.pipe(util2.setExecutableBit(['**/*.sh']));
}

View file

@ -111,12 +111,17 @@ function toBundleStream(src, bundledFileHeader, bundles) {
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
}));
}
const DEFAULT_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
function optimizeTask(opts) {
const src = opts.src;
const entryPoints = opts.entryPoints;
const resources = opts.resources;
const loaderConfig = opts.loaderConfig;
const bundledFileHeader = opts.header;
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
const out = opts.out;
return function () {

View file

@ -154,7 +154,7 @@ export interface IOptimizeTaskOpts {
/**
* (basically the Copyright treatment)
*/
header: string;
header?: string;
/**
* (emit bundleInfo.json file)
*/
@ -169,12 +169,18 @@ export interface IOptimizeTaskOpts {
languages?: Language[];
}
const DEFAULT_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
const src = opts.src;
const entryPoints = opts.entryPoints;
const resources = opts.resources;
const loaderConfig = opts.loaderConfig;
const bundledFileHeader = opts.header;
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
const out = opts.out;

View file

@ -6,6 +6,6 @@
"private": true,
"license": "MIT",
"devDependencies": {
"gulp-watch": "^4.3.9"
"gulp-watch": "5.0.1"
}
}

File diff suppressed because it is too large Load diff

View file

@ -35,6 +35,8 @@ yarnInstall('extensions'); // node modules shared by all extensions
yarnInstall('remote'); // node modules used by vscode server
yarnInstall('remote/web'); // node modules used by vscode web
const allExtensionFolders = fs.readdirSync('extensions');
const extensions = allExtensionFolders.filter(e => {
try {

View file

@ -1,2 +1,3 @@
test/**
cgmanifest.json
.vscode

View file

@ -2,4 +2,5 @@ src/**
tsconfig.json
out/**
extension.webpack.config.js
yarn.lock
yarn.lock
.vscode

View file

@ -6,3 +6,4 @@ extension.webpack.config.js
CONTRIBUTING.md
cgmanifest.json
yarn.lock
.vscode

View file

@ -1,32 +0,0 @@
{
"registrations": [
{
"component": {
"type": "git",
"git": {
"name": "textmate/markdown.tmbundle",
"repositoryUrl": "https://github.com/textmate/markdown.tmbundle",
"commitHash": "11cf764606cb2cde54badb5d0e5a0758a8871c4b"
}
},
"licenseDetail": [
"Copyright (c) markdown.tmbundle authors",
"",
"If not otherwise specified (see below), files in this repository fall under the following license:",
"",
"Permission to copy, use, modify, sell and distribute this",
"software is granted. This software is provided \"as is\" without",
"express or implied warranty, and with no claim as to its",
"suitability for any purpose.",
"",
"An exception is made for files in readable text which contain their own license information,",
"or files where an accompanying file exists (in the same directory) with a \"-license\" suffix added",
"to the base-name name of the original file, and an extension of txt, html, or similar. For example",
"\"tidy\" is accompanied by \"tidy-license.txt\"."
],
"license": "TextMate Bundle License",
"version": "0.0.0"
}
],
"version": 1
}

View file

@ -4,3 +4,4 @@ out/test/**
src/**
tsconfig.json
cgmanifest.json
.vscode

View file

@ -3,3 +3,4 @@ src/**
tsconfig.json
extension.webpack.config.js
cgmanifest.json
.vscode

View file

@ -270,27 +270,6 @@ suite('window namespace tests', () => {
window.createTerminal({ name: 'c', virtualProcess });
});
test('should get dimensions event when shown', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
reg1.dispose();
equal(terminal, term);
term.show();
});
const virtualProcess: TerminalVirtualProcess = {
onDidWrite: new EventEmitter<string>().event,
setDimensions: dimensions => {
ok(dimensions.columns > 0);
ok(dimensions.rows > 0);
const reg2 = window.onDidCloseTerminal(() => {
reg2.dispose();
done();
});
terminal.dispose();
}
};
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
});
test('should fire Terminal.onData on write', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term);
@ -313,6 +292,26 @@ suite('window namespace tests', () => {
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
});
test('should fire provide dimensions on start as the terminal has been shown', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term);
reg1.dispose();
});
const virtualProcess: TerminalVirtualProcess = {
onDidWrite: new EventEmitter<string>().event,
start: (dimensions) => {
ok(dimensions!.columns > 0);
ok(dimensions!.rows > 0);
const reg3 = window.onDidCloseTerminal(() => {
reg3.dispose();
done();
});
terminal.dispose();
}
};
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
});
test('should respect dimension overrides', (done) => {
const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term);

View file

@ -1 +0,0 @@
node_modules

View file

@ -1,7 +1,7 @@
{
"name": "code-oss-dev",
"version": "1.37.0",
"distro": "4d4ca170652edf13efd5916e009bdc9c0d4d1103",
"distro": "a76f8ddb784119243aa004071cea17c5a74b1e60",
"author": {
"name": "Microsoft Corporation"
},
@ -29,7 +29,6 @@
},
"dependencies": {
"applicationinsights": "1.0.8",
"getmac": "1.4.1",
"graceful-fs": "4.1.11",
"http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1",
@ -157,4 +156,4 @@
"windows-mutex": "0.2.1",
"windows-process-tree": "0.2.4"
}
}
}

3
remote/web/.yarnrc Normal file
View file

@ -0,0 +1,3 @@
disturl "http://nodejs.org/dist"
target "10.11.0"
runtime "node"

11
remote/web/package.json Normal file
View file

@ -0,0 +1,11 @@
{
"name": "vscode-web",
"version": "0.0.0",
"dependencies": {
"onigasm-umd": "^2.2.2",
"vscode-textmate": "^4.1.1",
"xterm": "3.15.0-beta67",
"xterm-addon-search": "0.2.0-beta2",
"xterm-addon-web-links": "0.1.0-beta10"
}
}

42
remote/web/yarn.lock Normal file
View file

@ -0,0 +1,42 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
nan@^2.14.0:
version "2.14.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
onigasm-umd@^2.2.2:
version "2.2.2"
resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257"
integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw==
oniguruma@^7.2.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.2.0.tgz#c9a59c1ea7b9fe67e237a02e02139b638856f3af"
integrity sha512-bh+ZLdykY1sdIx8jBp2zpLbVFDBc3XmKH4Ceo2lijNaN1WhEqtnpqFlmtCbRuDB17nJ58RAUStVwfW8e8uEbnA==
dependencies:
nan "^2.14.0"
vscode-textmate@^4.1.1:
version "4.2.2"
resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.2.2.tgz#0b4dabc69a6fba79a065cb6b615f66eac07c8f4c"
integrity sha512-1U4ih0E/KP1zNK/EbpUqyYtI7PY+Ccd2nDGTtiMR/UalLFnmaYkwoWhN1oI7B91ptBN8NdVwWuvyUnvJAulCUw==
dependencies:
oniguruma "^7.2.0"
xterm-addon-search@0.2.0-beta2:
version "0.2.0-beta2"
resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262"
integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g==
xterm-addon-web-links@0.1.0-beta10:
version "0.1.0-beta10"
resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23"
integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg==
xterm@3.15.0-beta67:
version "3.15.0-beta67"
resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta67.tgz#71973e174bdc08df620945eecd3f87912f1ac550"
integrity sha512-qLfo9GHVlu/IxgDI3vRGObWZM7UL4eLhMfjZhprx2aXNMpzmrOW6l3JDRsCjUWm93EoVavbULtnDhGSiTlKitQ==

View file

@ -15,7 +15,7 @@ import { ButtonGroup, IButtonStyles } from 'vs/base/browser/ui/button/button';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { isMacintosh } from 'vs/base/common/platform';
import { isMacintosh, isLinux } from 'vs/base/common/platform';
export interface IDialogOptions {
cancelId?: number;
@ -97,9 +97,9 @@ export class Dialog extends Disposable {
clearNode(this.buttonsContainer);
let focusedButton = 0;
this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true });
const buttonGroup = this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true });
const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId);
this.buttonGroup.buttons.forEach((button, index) => {
buttonGroup.buttons.forEach((button, index) => {
button.label = mnemonicButtonLabel(buttonMap[index].label, true);
this._register(button.onDidClick(e => {
@ -115,18 +115,16 @@ export class Dialog extends Disposable {
}
let eventHandled = false;
if (this.buttonGroup) {
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1;
focusedButton = focusedButton % this.buttonGroup.buttons.length;
this.buttonGroup.buttons[focusedButton].focus();
eventHandled = true;
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
focusedButton++;
focusedButton = focusedButton % this.buttonGroup.buttons.length;
this.buttonGroup.buttons[focusedButton].focus();
eventHandled = true;
}
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
focusedButton = focusedButton + buttonGroup.buttons.length - 1;
focusedButton = focusedButton % buttonGroup.buttons.length;
buttonGroup.buttons[focusedButton].focus();
eventHandled = true;
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
focusedButton++;
focusedButton = focusedButton % buttonGroup.buttons.length;
buttonGroup.buttons[focusedButton].focus();
eventHandled = true;
}
if (eventHandled) {
@ -192,7 +190,11 @@ export class Dialog extends Disposable {
show(this.element);
// Focus first element
this.buttonGroup.buttons[focusedButton].focus();
buttonMap.forEach((value, index) => {
if (value.index === focusedButton) {
buttonGroup.buttons[index].focus();
}
});
});
}
@ -243,7 +245,8 @@ export class Dialog extends Disposable {
buttonMap.push({ label: button, index: index });
});
if (isMacintosh) {
// macOS/linux: reverse button order
if (isMacintosh || isLinux) {
if (cancelId !== undefined) {
const cancelButton = buttonMap.splice(cancelId, 1)[0];
buttonMap.reverse();

View file

@ -329,6 +329,7 @@ export function mightProducePrintableCharacter(event: IKeyboardEvent): boolean {
return (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)
|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9)
|| (event.keyCode >= KeyCode.NUMPAD_0 && event.keyCode <= KeyCode.NUMPAD_9)
|| (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE);
}

View file

@ -212,7 +212,13 @@ export class Sash extends Disposable {
return;
}
const iframes = getElementsByTagName('iframe');
// Select both iframes and webviews; internally Electron nests an iframe
// in its <webview> component, but this isn't queryable.
const iframes = [
...getElementsByTagName('iframe'),
...getElementsByTagName('webview'),
];
for (const iframe of iframes) {
iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash
}
@ -280,7 +286,6 @@ export class Sash extends Disposable {
dispose(disposables);
const iframes = getElementsByTagName('iframe');
for (const iframe of iframes) {
iframe.style.pointerEvents = 'auto';
}

View file

@ -41,6 +41,10 @@
position: relative;
}
.monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) {
display: none;
}
.monaco-split-view2.vertical > .split-view-container > .split-view-view {
width: 100%;
}

View file

@ -47,7 +47,9 @@ export interface IView {
readonly maximumSize: number;
readonly onDidChange: Event<number | undefined>;
readonly priority?: LayoutPriority;
readonly snap?: boolean;
layout(size: number, orientation: Orientation): void;
setVisible?(visible: boolean): void;
}
interface ISashEvent {
@ -57,12 +59,79 @@ interface ISashEvent {
alt: boolean;
}
interface IViewItem {
view: IView;
size: number;
container: HTMLElement;
disposable: IDisposable;
layout(): void;
abstract class ViewItem {
set size(size: number) {
this._size = size;
}
get size(): number {
return this._size;
}
private cachedSize: number | undefined = undefined;
get visible(): boolean {
return typeof this.cachedSize === 'undefined';
}
set visible(visible: boolean) {
if (visible === this.visible) {
return;
}
if (visible) {
this.size = this.cachedSize!;
this.cachedSize = undefined;
} else {
this.cachedSize = this.size;
this.size = 0;
}
dom.toggleClass(this.container, 'visible', visible);
if (this.view.setVisible) {
this.view.setVisible(visible);
}
}
get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; }
get viewMinimumSize(): number { return this.view.minimumSize; }
get maximumSize(): number { return this.visible ? this.view.maximumSize : 0; }
get viewMaximumSize(): number { return this.view.maximumSize; }
get priority(): LayoutPriority | undefined { return this.view.priority; }
get snap(): boolean { return !!this.view.snap; }
constructor(protected container: HTMLElement, private view: IView, private _size: number, private disposable: IDisposable) {
dom.addClass(container, 'visible');
}
abstract layout(): void;
layoutView(orientation: Orientation): void {
this.view.layout(this.size, orientation);
}
dispose(): IView {
this.disposable.dispose();
return this.view;
}
}
class VerticalViewItem extends ViewItem {
layout(): void {
this.container.style.height = `${this.size}px`;
this.layoutView(Orientation.VERTICAL);
}
}
class HorizontalViewItem extends ViewItem {
layout(): void {
this.container.style.width = `${this.size}px`;
this.layoutView(Orientation.HORIZONTAL);
}
}
interface ISashItem {
@ -78,6 +147,8 @@ interface ISashDragState {
minDelta: number;
maxDelta: number;
alt: boolean;
snapIndex: number | undefined;
snapLimitDelta: number | undefined;
disposable: IDisposable;
}
@ -104,7 +175,7 @@ export class SplitView extends Disposable {
private size = 0;
private contentSize = 0;
private proportions: undefined | number[] = undefined;
private viewItems: IViewItem[] = [];
private viewItems: ViewItem[] = [];
private sashItems: ISashItem[] = [];
private sashDragState: ISashDragState;
private state: State = State.Idle;
@ -122,11 +193,11 @@ export class SplitView extends Disposable {
}
get minimumSize(): number {
return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0);
return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
}
get maximumSize(): number {
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0);
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);
}
private _orthogonalStartSash: Sash | undefined;
@ -201,15 +272,6 @@ export class SplitView extends Disposable {
const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));
const disposable = combinedDisposable(onChangeDisposable, containerDisposable);
const layoutContainer = this.orientation === Orientation.VERTICAL
? () => item.container.style.height = `${item.size}px`
: () => item.container.style.width = `${item.size}px`;
const layout = () => {
layoutContainer();
item.view.layout(item.size, this.orientation);
};
let viewSize: number;
if (typeof size === 'number') {
@ -220,7 +282,10 @@ export class SplitView extends Disposable {
viewSize = view.minimumSize;
}
const item: IViewItem = { view, container, size: viewSize, layout, disposable };
const item = this.orientation === Orientation.VERTICAL
? new VerticalViewItem(container, view, viewSize, disposable)
: new HorizontalViewItem(container, view, viewSize, disposable);
this.viewItems.splice(index, 0, item);
// Add sash
@ -280,7 +345,7 @@ export class SplitView extends Disposable {
// Remove view
const viewItem = this.viewItems.splice(index, 1)[0];
viewItem.disposable.dispose();
const view = viewItem.dispose();
// Remove sash
if (this.viewItems.length >= 1) {
@ -296,7 +361,7 @@ export class SplitView extends Disposable {
this.distributeViewSizes();
}
return viewItem.view;
return view;
}
moveView(from: number, to: number): void {
@ -327,6 +392,27 @@ export class SplitView extends Disposable {
this.addView(fromView, toSize, to);
}
isViewVisible(index: number): boolean {
if (index < 0 || index >= this.viewItems.length) {
throw new Error('Index out of bounds');
}
const viewItem = this.viewItems[index];
return viewItem.visible;
}
setViewVisible(index: number, visible: boolean): void {
if (index < 0 || index >= this.viewItems.length) {
throw new Error('Index out of bounds');
}
const viewItem = this.viewItems[index];
viewItem.visible = visible;
this.distributeEmptySpace(index);
this.layoutViews();
}
private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void {
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined;
@ -344,14 +430,14 @@ export class SplitView extends Disposable {
if (!this.proportions) {
const indexes = range(this.viewItems.length);
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.Low);
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.High);
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);
} else {
for (let i = 0; i < this.viewItems.length; i++) {
const item = this.viewItems[i];
item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize);
item.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize);
}
}
@ -391,35 +477,72 @@ export class SplitView extends Disposable {
if (isLastSash) {
const viewItem = this.viewItems[index];
minDelta = (viewItem.view.minimumSize - viewItem.size) / 2;
maxDelta = (viewItem.view.maximumSize - viewItem.size) / 2;
minDelta = (viewItem.minimumSize - viewItem.size) / 2;
maxDelta = (viewItem.maximumSize - viewItem.size) / 2;
} else {
const viewItem = this.viewItems[index + 1];
minDelta = (viewItem.size - viewItem.view.maximumSize) / 2;
maxDelta = (viewItem.size - viewItem.view.minimumSize) / 2;
minDelta = (viewItem.size - viewItem.maximumSize) / 2;
maxDelta = (viewItem.size - viewItem.minimumSize) / 2;
}
}
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, disposable };
let snapIndex: number | undefined;
let snapLimitDelta: number | undefined;
if (!alt) {
const upIndexes = range(index, -1);
const downIndexes = range(index + 1, this.viewItems.length);
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);
const minDelta = Math.max(minDeltaUp, minDeltaDown);
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp);
const snapBefore = this.viewItems[index].snap;
const snapAfter = this.viewItems[index + 1].snap;
if (snapBefore && snapAfter) {
snapIndex = index + 1 < (this.viewItems.length - index - 1) ? index : index + 1;
} else if (snapBefore) {
snapIndex = index;
} else if (snapAfter) {
snapIndex = index + 1;
}
if (typeof snapIndex === 'number') {
if (this.viewItems[snapIndex].visible) {
snapLimitDelta = snapIndex === index
? minDelta - (this.viewItems[index].viewMinimumSize / 2)
: maxDelta + (this.viewItems[index + 1].viewMinimumSize / 2);
} else {
snapLimitDelta = snapIndex === index
? minDelta + (this.viewItems[index].viewMinimumSize / 2)
: maxDelta - (this.viewItems[index + 1].viewMinimumSize / 2);
}
}
}
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapIndex, snapLimitDelta, disposable };
};
resetSashDragState(start, alt);
}
private onSashChange({ current }: ISashEvent): void {
const { index, start, sizes, alt, minDelta, maxDelta } = this.sashDragState;
const { index, start, sizes, alt, minDelta, maxDelta, snapIndex, snapLimitDelta } = this.sashDragState;
this.sashDragState.current = current;
const delta = current - start;
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta);
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapIndex, snapLimitDelta);
if (alt) {
const isLastSash = index === this.sashItems.length - 1;
const newSizes = this.viewItems.map(i => i.size);
const viewItemIndex = isLastSash ? index : index + 1;
const viewItem = this.viewItems[viewItemIndex];
const newMinDelta = viewItem.size - viewItem.view.maximumSize;
const newMaxDelta = viewItem.size - viewItem.view.minimumSize;
const newMinDelta = viewItem.size - viewItem.maximumSize;
const newMaxDelta = viewItem.size - viewItem.minimumSize;
const resizeIndex = isLastSash ? index - 1 : index + 1;
this.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta);
@ -435,7 +558,7 @@ export class SplitView extends Disposable {
this.saveProportions();
}
private onViewChange(item: IViewItem, size: number | undefined): void {
private onViewChange(item: ViewItem, size: number | undefined): void {
const index = this.viewItems.indexOf(item);
if (index < 0 || index >= this.viewItems.length) {
@ -443,7 +566,7 @@ export class SplitView extends Disposable {
}
size = typeof size === 'number' ? size : item.size;
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
size = clamp(size, item.minimumSize, item.maximumSize);
if (this.inverseAltBehavior && index > 0) {
// In this case, we want the view to grow or shrink both sides equally
@ -470,13 +593,13 @@ export class SplitView extends Disposable {
const item = this.viewItems[index];
size = Math.round(size);
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
size = clamp(size, item.minimumSize, item.maximumSize);
let delta = size - item.size;
if (delta !== 0 && index < this.viewItems.length - 1) {
const downIndexes = range(index + 1, this.viewItems.length);
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
const deltaDown = clamp(delta, -expandDown, collapseDown);
this.resize(index, deltaDown);
@ -485,8 +608,8 @@ export class SplitView extends Disposable {
if (delta !== 0 && index > 0) {
const upIndexes = range(index - 1, -1);
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
const deltaUp = clamp(-delta, -collapseUp, expandUp);
this.resize(index - 1, deltaUp);
@ -521,7 +644,9 @@ export class SplitView extends Disposable {
lowPriorityIndexes?: number[],
highPriorityIndexes?: number[],
overloadMinDelta: number = Number.NEGATIVE_INFINITY,
overloadMaxDelta: number = Number.POSITIVE_INFINITY
overloadMaxDelta: number = Number.POSITIVE_INFINITY,
snapIndex?: number,
snapLimitDelta?: number
): number {
if (index < 0 || index >= this.viewItems.length) {
return 0;
@ -550,18 +675,28 @@ export class SplitView extends Disposable {
const downItems = downIndexes.map(i => this.viewItems[i]);
const downSizes = downIndexes.map(i => sizes[i]);
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0);
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0);
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0);
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0);
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);
const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);
if (typeof snapIndex === 'number' && typeof snapLimitDelta === 'number') {
const snapView = this.viewItems[snapIndex];
snapView.visible = snapIndex === index
? delta >= snapLimitDelta // up
: delta < snapLimitDelta; // down
return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);
}
delta = clamp(delta, minDelta, maxDelta);
for (let i = 0, deltaUp = delta; i < upItems.length; i++) {
const item = upItems[i];
const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize);
const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);
const viewDelta = size - upSizes[i];
deltaUp -= viewDelta;
@ -570,7 +705,7 @@ export class SplitView extends Disposable {
for (let i = 0, deltaDown = delta; i < downItems.length; i++) {
const item = downItems[i];
const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize);
const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);
const viewDelta = size - downSizes[i];
deltaDown += viewDelta;
@ -580,13 +715,19 @@ export class SplitView extends Disposable {
return delta;
}
private distributeEmptySpace(): void {
let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
private distributeEmptySpace(lowPriorityIndex?: number): void {
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
let emptyDelta = this.size - contentSize;
for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) {
const item = this.viewItems[i];
const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize);
const indexes = range(this.viewItems.length - 1, -1);
if (typeof lowPriorityIndex === 'number') {
pushToEnd(indexes, lowPriorityIndex);
}
for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {
const item = this.viewItems[indexes[i]];
const size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize);
const viewDelta = size - item.size;
emptyDelta -= viewDelta;
@ -606,30 +747,43 @@ export class SplitView extends Disposable {
// Update sashes enablement
let previous = false;
const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous);
const collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous);
previous = false;
const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous);
const expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous);
const reverseViews = [...this.viewItems].reverse();
previous = false;
const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse();
const collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse();
previous = false;
const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse();
const expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse();
this.sashItems.forEach((s, i) => {
const min = !(collapsesDown[i] && expandsUp[i + 1]);
const max = !(expandsDown[i] && collapsesUp[i + 1]);
if (min && max) {
if (!this.viewItems[i].visible) {
s.sash.state = SashState.Disabled;
} else if (min && !max) {
s.sash.state = SashState.Minimum;
} else if (!min && max) {
s.sash.state = SashState.Maximum;
} else {
s.sash.state = SashState.Enabled;
const min = !(collapsesDown[i] && expandsUp[i + 1]);
const max = !(expandsDown[i] && collapsesUp[i + 1]);
if (min && max) {
const before = !range(0, i + 1).some(i => !this.viewItems[i].snap || this.viewItems[i].visible);
const after = !range(i + 1, this.viewItems.length).some(i => !this.viewItems[i].snap || this.viewItems[i].visible);
if (before) {
s.sash.state = SashState.Minimum;
} else if (after) {
s.sash.state = SashState.Maximum;
} else {
s.sash.state = SashState.Disabled;
}
} else if (min && !max) {
s.sash.state = SashState.Minimum;
} else if (!min && max) {
s.sash.state = SashState.Maximum;
} else {
s.sash.state = SashState.Enabled;
}
}
});
}
@ -651,7 +805,7 @@ export class SplitView extends Disposable {
dispose(): void {
super.dispose();
this.viewItems.forEach(i => i.disposable.dispose());
this.viewItems.forEach(i => i.dispose());
this.viewItems = [];
this.sashItems.forEach(i => i.disposable.dispose());

View file

@ -17,5 +17,5 @@
}
.hc-black .monaco-toolbar .action-label.toolbar-toggle-more {
background-image: url('ellipsis-dark.svg');
background-image: url('ellipsis-hc.svg');
}

View file

@ -7,6 +7,7 @@ import * as errors from 'vs/base/common/errors';
import * as uuid from 'vs/base/common/uuid';
import { networkInterfaces } from 'os';
import { TernarySearchTree } from 'vs/base/common/map';
import { getMac } from 'vs/base/node/macAddress';
// http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/
// VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69
@ -76,35 +77,25 @@ export const virtualMachineHint: { value(): number } = new class {
};
let machineId: Promise<string>;
export function getMachineId(): Promise<string> {
return machineId || (machineId = getMacMachineId()
.then(id => id || uuid.generateUuid())); // fallback, generate a UUID
export async function getMachineId(): Promise<string> {
if (!machineId) {
machineId = (async () => {
const id = await getMacMachineId();
return id || uuid.generateUuid(); // fallback, generate a UUID
})();
}
return machineId;
}
function getMacMachineId(): Promise<string> {
return new Promise<string>(resolve => {
Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => {
try {
getmac.getMac((error, macAddress) => {
if (!error) {
resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex'));
} else {
resolve(undefined);
}
});
// Timeout due to hang with reduced privileges #58392
// TODO@sbatten: Remove this when getmac is patched
setTimeout(() => {
resolve(undefined);
}, 10000);
} catch (err) {
errors.onUnexpectedError(err);
resolve(undefined);
}
}, err => {
errors.onUnexpectedError(err);
resolve(undefined);
});
});
async function getMacMachineId(): Promise<string | undefined> {
try {
const crypto = await import('crypto');
const macAddress = await getMac();
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
} catch (err) {
errors.onUnexpectedError(err);
return undefined;
}
}

View file

@ -0,0 +1,69 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { exec } from 'child_process';
import { isWindows } from 'vs/base/common/platform';
const cmdline = {
windows: 'getmac.exe',
unix: '/sbin/ifconfig -a || /sbin/ip link'
};
const invalidMacAddresses = [
'00:00:00:00:00:00',
'ff:ff:ff:ff:ff:ff',
'ac:de:48:00:11:22'
];
function validateMacAddress(candidate: string): boolean {
let tempCandidate = candidate.replace(/\-/g, ':').toLowerCase();
for (let invalidMacAddress of invalidMacAddresses) {
if (invalidMacAddress === tempCandidate) {
return false;
}
}
return true;
}
export function getMac(): Promise<string> {
return new Promise(async (resolve, reject) => {
const timeout = setTimeout(() => reject('Unable to retrieve mac address (timeout after 10s)'), 10000);
try {
resolve(await doGetMac());
} catch (error) {
reject(error);
} finally {
clearTimeout(timeout);
}
});
}
function doGetMac(): Promise<string> {
return new Promise((resolve, reject) => {
try {
exec(isWindows ? cmdline.windows : cmdline.unix, { timeout: 10000 }, (err, stdout, stdin) => {
if (err) {
return reject(`Unable to retrieve mac address (${err.toString()})`);
} else {
const regex = /(?:[a-f\d]{2}[:\-]){5}[a-f\d]{2}/gi;
let match;
while ((match = regex.exec(stdout)) !== null) {
const macAddressCandidate = match[0];
if (validateMacAddress(macAddressCandidate)) {
return resolve(macAddressCandidate);
}
}
return reject('Unable to retrieve mac address (unexpected format)');
}
});
} catch (err) {
reject(err);
}
});
}

View file

@ -3,8 +3,8 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import * as getmac from 'getmac';
import { getMachineId } from 'vs/base/node/id';
import { getMac } from 'vs/base/node/macAddress';
suite('ID', () => {
@ -16,9 +16,7 @@ suite('ID', () => {
});
test('getMac', () => {
return new Promise<string>((resolve, reject) => {
getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress));
}).then(macAddress => {
return getMac().then(macAddress => {
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`);
});
});

View file

@ -16,7 +16,7 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
import { IRequestService } from 'vs/platform/request/common/request';
@ -55,6 +55,8 @@ import { FileService } from 'vs/platform/files/common/fileService';
import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import { IProductService } from 'vs/platform/product/common/product';
import { ProductService } from 'vs/platform/product/node/productService';
export interface ISharedProcessConfiguration {
readonly machineId: string;
@ -114,6 +116,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IConfigurationService, configurationService);
services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IDownloadService, new SyncDescriptor(DownloadService));
services.set(IProductService, new SyncDescriptor(ProductService));
const mainProcessService = new MainProcessService(server, mainRouter);
services.set(IMainProcessService, mainProcessService);

View file

@ -90,6 +90,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
export class CodeApplication extends Disposable {
private static readonly MACHINE_ID_KEY = 'telemetry.machineId';
private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId';
private windowsMainService: IWindowsMainService | undefined;
@ -363,8 +364,8 @@ export class CodeApplication extends Disposable {
// Resolve unique machine ID
this.logService.trace('Resolving machine identifier...');
const machineId = await this.resolveMachineId();
this.logService.trace(`Resolved machine identifier: ${machineId}`);
const { machineId, trueMachineId } = await this.resolveMachineId();
this.logService.trace(`Resolved machine identifier: ${machineId} (trueMachineId: ${trueMachineId})`);
// Spawn shared process after the first window has opened and 3s have passed
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
@ -378,7 +379,7 @@ export class CodeApplication extends Disposable {
});
// Services
const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient);
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient);
// Create driver
if (this.environmentService.driverHandle) {
@ -404,7 +405,7 @@ export class CodeApplication extends Disposable {
}
}
private async resolveMachineId(): Promise<string> {
private async resolveMachineId(): Promise<{ machineId: string, trueMachineId?: string }> {
// We cache the machineId for faster lookups on startup
// and resolve it only once initially if not cached
@ -415,10 +416,21 @@ export class CodeApplication extends Disposable {
this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId);
}
return machineId;
// Check if machineId is hashed iBridge Device
let trueMachineId: string | undefined;
if (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead') {
trueMachineId = this.stateService.getItem<string>(CodeApplication.TRUE_MACHINE_ID_KEY);
if (!trueMachineId) {
trueMachineId = await getMachineId();
this.stateService.setItem(CodeApplication.TRUE_MACHINE_ID_KEY, trueMachineId);
}
}
return { machineId, trueMachineId };
}
private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
const services = new ServiceCollection();
// Files
@ -473,7 +485,7 @@ export class CodeApplication extends Disposable {
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath);
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId };
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
} else {

View file

@ -21,10 +21,12 @@ import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/worksp
import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import * as perf from 'vs/base/common/performance';
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { endsWith } from 'vs/base/common/strings';
import { RunOnceScheduler } from 'vs/base/common/async';
import { IFileService } from 'vs/platform/files/common/files';
import pkg from 'vs/platform/product/node/package';
const RUN_TEXTMATE_IN_WORKER = false;
@ -76,6 +78,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
config: IWindowCreationOptions,
@ILogService private readonly logService: ILogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@IThemeMainService private readonly themeMainService: IThemeMainService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@ -307,7 +310,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
private handleMarketplaceRequests(): void {
// Resolve marketplace headers
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.environmentService);
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(pkg.version, this.environmentService, this.fileService);
// Inject headers when requests are incoming
const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*'];

View file

@ -207,46 +207,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers());
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex());
}
private setupNativeHelpers(): void {
private installWindowsMutex(): void {
if (isWindows) {
// Setup Windows mutex
try {
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
const mutex = new WindowsMutex(product.win32MutexName);
once(this.lifecycleService.onWillShutdown)(() => mutex.release());
} catch (e) {
this.logService.error(e);
if (!this.environmentService.isBuilt) {
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-mutex!',
detail: e.toString(),
noLink: true
});
}
}
// Dev only: Ensure Windows foreground love module is present
if (!this.environmentService.isBuilt) {
try {
require.__$__nodeRequire('windows-foreground-love');
} catch (e) {
this.logService.error(e);
this.showMessageBox({
title: product.nameLong,
type: 'warning',
message: 'Failed to load windows-foreground-love!',
detail: e.toString(),
noLink: true
});
}
}
}
}

View file

@ -17,7 +17,7 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
@ -46,6 +46,8 @@ import { FileService } from 'vs/platform/files/common/fileService';
import { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IProductService } from 'vs/platform/product/common/product';
import { ProductService } from 'vs/platform/product/node/productService';
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
@ -301,6 +303,7 @@ export async function main(argv: ParsedArgs): Promise<void> {
services.set(ILogService, logService);
services.set(IConfigurationService, configurationService);
services.set(IStateService, new SyncDescriptor(StateService));
services.set(IProductService, new SyncDescriptor(ProductService));
// Files
const fileService = new FileService(logService);

View file

@ -0,0 +1,28 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { isWindows } from 'vs/base/common/platform';
suite('Windows Native Helpers', () => {
test('windows-mutex', async () => {
if (!isWindows) {
return;
}
const mutex = await import('windows-mutex');
assert.ok(mutex, 'Unable to load windows-mutex dependency.');
assert.ok(typeof mutex.isActive === 'function', 'Unable to load windows-mutex dependency.');
});
test('windows-foreground-love', async () => {
if (!isWindows) {
return;
}
const foregroundLove = await import('windows-foreground-love');
assert.ok(foregroundLove, 'Unable to load windows-foreground-love dependency.');
});
});

View file

@ -80,7 +80,7 @@ export class QuickFixController extends Disposable implements IEditorContributio
this._ui.update(newState);
}
public showCodeActions(actions: Promise<CodeActionSet>, at: IAnchor | IPosition) {
public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) {
return this._ui.showCodeActionList(actions, at);
}

View file

@ -95,15 +95,7 @@ export class CodeActionUi extends Disposable {
}
}
public async showCodeActionList(codeActions: Promise<CodeActionSet>, at?: IAnchor | IPosition): Promise<void> {
let actions: CodeActionSet;
try {
actions = await codeActions;
} catch (e) {
onUnexpectedError(e);
return;
}
public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise<void> {
this._codeActionWidget.show(actions, at);
}

View file

@ -13,7 +13,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
import { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor, CodeAction } from 'vs/editor/common/modes';
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes';
import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';
import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';
@ -517,21 +517,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
const hoverElement = $('div.hover-row.status-bar');
const disposables = new DisposableStore();
const actionsElement = dom.append(hoverElement, $('div.actions'));
disposables.add(this.renderAction(actionsElement, {
label: nls.localize('quick fixes', "Quick Fix..."),
commandId: QuickFixAction.Id,
run: async (target) => {
const codeActionsPromise = this.getCodeActions(markerHover.marker);
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
const controller = QuickFixController.get(this._editor);
const elementPosition = dom.getDomNodePagePosition(target);
controller.showCodeActions(codeActionsPromise, {
x: elementPosition.left + 6,
y: elementPosition.top + elementPosition.height + 6
});
}
}));
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
disposables.add(this.renderAction(actionsElement, {
label: nls.localize('peek problem', "Peek Problem"),
@ -543,27 +528,61 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
}
}));
}
const quickfixPlaceholderElement = dom.append(actionsElement, $('div'));
quickfixPlaceholderElement.style.opacity = '0';
quickfixPlaceholderElement.style.transition = 'opacity 0.2s';
setTimeout(() => quickfixPlaceholderElement.style.opacity = '1', 200);
quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes...");
disposables.add(toDisposable(() => quickfixPlaceholderElement.remove()));
const codeActionsPromise = this.getCodeActions(markerHover.marker);
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
codeActionsPromise.then(actions => {
quickfixPlaceholderElement.style.transition = '';
quickfixPlaceholderElement.style.opacity = '1';
if (!actions.actions.length) {
actions.dispose();
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
return;
}
quickfixPlaceholderElement.remove();
let showing = false;
disposables.add(toDisposable(() => {
if (!showing) {
actions.dispose();
}
}));
disposables.add(this.renderAction(actionsElement, {
label: nls.localize('quick fixes', "Quick Fix..."),
commandId: QuickFixAction.Id,
run: (target) => {
showing = true;
const controller = QuickFixController.get(this._editor);
const elementPosition = dom.getDomNodePagePosition(target);
controller.showCodeActions(actions, {
x: elementPosition.left + 6,
y: elementPosition.top + elementPosition.height + 6
});
}
}));
});
this.renderDisposable.value = disposables;
return hoverElement;
}
private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> {
const noAction: CodeAction = {
title: nls.localize('editor.action.quickFix.noneMessage', "No code actions available"),
kind: CodeActionKind.QuickFix.value,
};
return createCancelablePromise(async (cancellationToken): Promise<CodeActionSet> => {
const result = await getCodeActions(
return createCancelablePromise(cancellationToken => {
return getCodeActions(
this._editor.getModel()!,
new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),
{ type: 'manual', filter: { kind: CodeActionKind.QuickFix } },
cancellationToken);
return {
actions: result.actions.length ? result.actions : [noAction],
hasAutoFix: result.hasAutoFix,
dispose: () => result.dispose(),
};
});
}

View file

@ -3,8 +3,6 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { tmpdir } from 'os';
import * as path from 'vs/base/common/path';
import { getErrorMessage, isPromiseCanceledError, canceled } from 'vs/base/common/errors';
import { StatisticType, IGalleryExtension, IExtensionGalleryService, IGalleryExtensionAsset, IQueryOptions, SortBy, SortOrder, IExtensionIdentifier, IReportedExtension, InstallOperation, ITranslation, IGalleryExtensionVersion, IGalleryExtensionAssets, isIExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement';
import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
@ -12,11 +10,8 @@ import { assign, getOrDefault } from 'vs/base/common/objects';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPager } from 'vs/base/common/paging';
import { IRequestService, IRequestOptions, IRequestContext, asJson, asText } from 'vs/platform/request/common/request';
import pkg from 'vs/platform/product/node/package';
import product from 'vs/platform/product/node/product';
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { writeFileSync, readFile } from 'vs/base/node/pfs';
import { generateUuid, isUUID } from 'vs/base/common/uuid';
import { values } from 'vs/base/common/map';
import { CancellationToken } from 'vs/base/common/cancellation';
@ -24,6 +19,9 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri';
import { joinPath } from 'vs/base/common/resources';
import { VSBuffer } from 'vs/base/common/buffer';
import { IProductService } from 'vs/platform/product/common/product';
interface IRawGalleryExtensionFile {
assetType: string;
@ -339,11 +337,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@ITelemetryService private readonly telemetryService: ITelemetryService,
@IFileService private readonly fileService: IFileService,
@IProductService private readonly productService: IProductService,
) {
const config = product.extensionsGallery;
const config = productService.extensionsGallery;
this.extensionsGalleryUrl = config && config.serviceUrl;
this.extensionsControlUrl = config && config.controlUrl;
this.commonHeadersPromise = resolveMarketplaceHeaders(this.environmentService);
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService);
}
private api(path = ''): string {
@ -356,7 +355,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise<IGalleryExtension | null> {
const extension: IGalleryExtension | null = isIExtensionIdentifier(arg1) ? null : arg1;
if (extension && extension.properties.engine && isEngineValid(extension.properties.engine)) {
if (extension && extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
return Promise.resolve(extension);
}
const { id, uuid } = extension ? extension.identifier : <IExtensionIdentifier>arg1;
@ -382,7 +381,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
if (versionAsset) {
const extension = toExtension(rawExtension, versionAsset, 0, query);
if (extension.properties.engine && isEngineValid(extension.properties.engine)) {
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
return extension;
}
}
@ -535,9 +534,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
});
}
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string> {
download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<URI> {
this.logService.trace('ExtensionGalleryService#download', extension.identifier.id);
const zipPath = path.join(tmpdir(), generateUuid());
const zip = joinPath(location, generateUuid());
const data = getGalleryExtensionTelemetryData(extension);
const startTime = new Date().getTime();
/* __GDPR__
@ -557,9 +556,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
} : extension.assets.download;
return this.getAsset(downloadAsset)
.then(context => this.fileService.writeFile(URI.file(zipPath), context.stream))
.then(context => this.fileService.writeFile(zip, context.stream))
.then(() => log(new Date().getTime() - startTime))
.then(() => zipPath);
.then(() => zip);
}
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
@ -615,7 +614,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
if (galleryExtensions.length) {
if (compatible) {
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine) ? v : null)))
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine, this.productService.version) ? v : null)))
.then(versions => versions
.filter(v => !!v)
.map(v => ({ version: v!.version, date: v!.lastUpdated })));
@ -701,7 +700,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
if (!engine) {
return null;
}
if (isEngineValid(engine)) {
if (isEngineValid(engine, this.productService.version)) {
return Promise.resolve(version);
}
}
@ -733,7 +732,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
const version = versions[0];
return this.getEngine(version)
.then(engine => {
if (!isEngineValid(engine)) {
if (!isEngineValid(engine, this.productService.version)) {
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
}
@ -774,24 +773,30 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
}
}
export function resolveMarketplaceHeaders(environmentService: IEnvironmentService): Promise<{ [key: string]: string; }> {
const marketplaceMachineIdFile = path.join(environmentService.userDataPath, 'machineid');
export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService): Promise<{ [key: string]: string; }> {
const marketplaceMachineIdFile = joinPath(URI.file(environmentService.userDataPath), 'machineid');
return readFile(marketplaceMachineIdFile, 'utf8')
.then<string | null>(contents => isUUID(contents) ? contents : null, () => null /* error reading ID file */)
.then(uuid => {
if (!uuid) {
uuid = generateUuid();
try {
writeFileSync(marketplaceMachineIdFile, uuid);
} catch (error) {
//noop
}
}
return {
'X-Market-Client-Id': `VSCode ${pkg.version}`,
'User-Agent': `VSCode ${pkg.version}`,
'X-Market-User-Id': uuid
};
});
let uuid: string | null = null;
try {
const contents = await fileService.readFile(marketplaceMachineIdFile);
const value = contents.value.toString();
uuid = isUUID(value) ? value : null;
} catch (e) {
uuid = null;
}
if (!uuid) {
uuid = generateUuid();
try {
await fileService.writeFile(marketplaceMachineIdFile, VSBuffer.fromString(uuid));
} catch (error) {
//noop
}
}
return {
'X-Market-Client-Id': `VSCode ${version}`,
'User-Agent': `VSCode ${version}`,
'X-Market-User-Id': uuid
};
}

View file

@ -151,7 +151,7 @@ export interface IExtensionGalleryService {
isEnabled(): boolean;
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string>;
download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<URI>;
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null>;

View file

@ -35,7 +35,7 @@ import { ExtensionsManifestCache } from 'vs/platform/extensionManagement/node/ex
import { ExtensionsLifecycle } from 'vs/platform/extensionManagement/node/extensionLifecycle';
import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
import { tmpdir } from 'os';
import { generateUuid } from 'vs/base/common/uuid';
import { IDownloadService } from 'vs/platform/download/common/download';
@ -197,7 +197,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
.then(manifest => {
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
let operation: InstallOperation = InstallOperation.Install;
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode)) {
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, pkg.version)) {
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", identifier.id, pkg.version)));
}
const identifierWithVersion = new ExtensionIdentifierWithVersion(identifier, manifest.version);
@ -391,9 +391,10 @@ export class ExtensionManagementService extends Disposable implements IExtension
};
this.logService.trace('Started downloading extension:', extension.identifier.id);
return this.galleryService.download(extension, operation)
return this.galleryService.download(extension, URI.file(tmpdir()), operation)
.then(
zipPath => {
zip => {
const zipPath = zip.fsPath;
this.logService.info('Downloaded extension:', extension.identifier.id, zipPath);
return getManifest(zipPath)
.then(

View file

@ -10,15 +10,32 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { join } from 'vs/base/common/path';
import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs';
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService';
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
import { isUUID } from 'vs/base/common/uuid';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { IFileService } from 'vs/platform/files/common/files';
import { FileService } from 'vs/platform/files/common/fileService';
import { NullLogService } from 'vs/platform/log/common/log';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network';
import pkg from 'vs/platform/product/node/package';
suite('Extension Gallery Service', () => {
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'extensiongalleryservice');
const marketplaceHome = join(parentDir, 'Marketplace');
let fileService: IFileService;
let disposables: DisposableStore;
setup(done => {
disposables = new DisposableStore();
fileService = new FileService(new NullLogService());
disposables.add(fileService);
const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService());
disposables.add(diskFileSystemProvider);
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
// Delete any existing backups completely and then re-create it.
rimraf(marketplaceHome, RimRafMode.MOVE).then(() => {
mkdirp(marketplaceHome).then(() => {
@ -28,6 +45,7 @@ suite('Extension Gallery Service', () => {
});
teardown(done => {
disposables.clear();
rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done);
});
@ -35,10 +53,10 @@ suite('Extension Gallery Service', () => {
const args = ['--user-data-dir', marketplaceHome];
const environmentService = new EnvironmentService(parseArgs(args), process.execPath);
return resolveMarketplaceHeaders(environmentService).then(headers => {
return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers => {
assert.ok(isUUID(headers['X-Market-User-Id']));
return resolveMarketplaceHeaders(environmentService).then(headers2 => {
return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers2 => {
assert.equal(headers['X-Market-User-Id'], headers2['X-Market-User-Id']);
});
});

View file

@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import pkg from 'vs/platform/product/node/package';
export interface IParsedVersion {
hasCaret: boolean;
@ -222,9 +221,9 @@ export function isValidExtensionVersion(version: string, extensionDesc: IReduced
return isVersionValid(version, extensionDesc.engines.vscode, notices);
}
export function isEngineValid(engine: string): boolean {
export function isEngineValid(engine: string, version: string): boolean {
// TODO@joao: discuss with alex '*' doesn't seem to be a valid engine version
return engine === '*' || isVersionValid(pkg.version, engine);
return engine === '*' || isVersionValid(version, engine);
}
export function isVersionValid(currentVersion: string, requestedVersion: string, notices: string[] = []): boolean {

View file

@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/node/extensionValidator';
import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator';
suite('Extension Version Validator', () => {

View file

@ -1696,7 +1696,9 @@ suite('Disk File Service', () => {
assert.ok(!error);
});
test('watch - file', done => {
const runWatchTests = isLinux;
(runWatchTests ? test : test.skip)('watch - file', done => {
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1705,11 +1707,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50);
});
test('watch - file symbolic link', async done => {
if (isWindows) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - file symbolic link', async done => {
const toWatch = URI.file(join(testDir, 'lorem.txt-linked'));
await symlink(join(testDir, 'lorem.txt'), toWatch.fsPath);
@ -1718,11 +1716,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50);
});
test('watch - file - multiple writes', done => {
if (isWindows) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - file - multiple writes', done => {
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1733,7 +1727,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes 3'), 20);
});
test('watch - file - delete file', done => {
(runWatchTests ? test : test.skip)('watch - file - delete file', done => {
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1742,11 +1736,7 @@ suite('Disk File Service', () => {
setTimeout(() => unlinkSync(toWatch.fsPath), 50);
});
test('watch - file - rename file', done => {
if (isWindows) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - file - rename file', done => {
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
const toWatchRenamed = URI.file(join(testDir, 'index-watch1-renamed.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1756,7 +1746,7 @@ suite('Disk File Service', () => {
setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50);
});
test('watch - file - rename file (different case)', done => {
(runWatchTests ? test : test.skip)('watch - file - rename file (different case)', done => {
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
const toWatchRenamed = URI.file(join(testDir, 'INDEX-watch1.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1770,7 +1760,7 @@ suite('Disk File Service', () => {
setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50);
});
test('watch - file (atomic save)', function (done) {
(runWatchTests ? test : test.skip)('watch - file (atomic save)', function (done) {
const toWatch = URI.file(join(testDir, 'index-watch2.html'));
writeFileSync(toWatch.fsPath, 'Init');
@ -1786,11 +1776,7 @@ suite('Disk File Service', () => {
}, 50);
});
test('watch - folder (non recursive) - change file', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - change file', done => {
const watchDir = URI.file(join(testDir, 'watch3'));
mkdirSync(watchDir.fsPath);
@ -1802,11 +1788,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
});
test('watch - folder (non recursive) - add file', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - add file', done => {
const watchDir = URI.file(join(testDir, 'watch4'));
mkdirSync(watchDir.fsPath);
@ -1817,11 +1799,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
});
test('watch - folder (non recursive) - delete file', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete file', done => {
const watchDir = URI.file(join(testDir, 'watch5'));
mkdirSync(watchDir.fsPath);
@ -1833,11 +1811,7 @@ suite('Disk File Service', () => {
setTimeout(() => unlinkSync(file.fsPath), 50);
});
test('watch - folder (non recursive) - add folder', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - add folder', done => {
const watchDir = URI.file(join(testDir, 'watch6'));
mkdirSync(watchDir.fsPath);
@ -1848,11 +1822,7 @@ suite('Disk File Service', () => {
setTimeout(() => mkdirSync(folder.fsPath), 50);
});
test('watch - folder (non recursive) - delete folder', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete folder', done => {
const watchDir = URI.file(join(testDir, 'watch7'));
mkdirSync(watchDir.fsPath);
@ -1864,11 +1834,7 @@ suite('Disk File Service', () => {
setTimeout(() => rimrafSync(folder.fsPath), 50);
});
test('watch - folder (non recursive) - symbolic link - change file', async done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - folder (non recursive) - symbolic link - change file', async done => {
const watchDir = URI.file(join(testDir, 'deep-link'));
await symlink(join(testDir, 'deep'), watchDir.fsPath);
@ -1880,11 +1846,7 @@ suite('Disk File Service', () => {
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
});
test('watch - folder (non recursive) - rename file', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - rename file', done => {
const watchDir = URI.file(join(testDir, 'watch8'));
mkdirSync(watchDir.fsPath);
@ -1898,11 +1860,7 @@ suite('Disk File Service', () => {
setTimeout(() => renameSync(file.fsPath, fileRenamed.fsPath), 50);
});
test('watch - folder (non recursive) - rename file (different case)', done => {
if (!isLinux) {
return done(); // watch tests are flaky on other platforms
}
(runWatchTests && isLinux /* this test requires a case sensitive file system */ ? test : test.skip)('watch - folder (non recursive) - rename file (different case)', done => {
const watchDir = URI.file(join(testDir, 'watch8'));
mkdirSync(watchDir.fsPath);

View file

@ -38,4 +38,10 @@ export class ProductService implements IProductService {
get settingsSearchBuildId(): number | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchBuildId : undefined; }
get settingsSearchUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchUrl : undefined; }
get experimentsUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.experimentsUrl : undefined; }
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return this.productConfiguration ? this.productConfiguration.extensionKeywords : undefined; }
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return this.productConfiguration ? this.productConfiguration.extensionAllowedBadgeProviders : undefined; }
}

View file

@ -33,6 +33,10 @@ export interface IProductService {
readonly settingsSearchBuildId?: number;
readonly settingsSearchUrl?: string;
readonly experimentsUrl?: string;
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
readonly extensionAllowedBadgeProviders?: readonly string[];
}
export interface IProductConfiguration {

View file

@ -33,4 +33,10 @@ export class ProductService implements IProductService {
get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; }
get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; }
get experimentsUrl(): string | undefined { return product.experimentsUrl; }
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return product.extensionKeywords; }
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return product.extensionAllowedBadgeProviders; }
}

View file

@ -12,22 +12,24 @@ import { VSBufferReadableStream, streamToBuffer } from 'vs/base/common/buffer';
export const IRequestService = createDecorator<IRequestService>('requestService');
export interface IHeaders {
[header: string]: string;
}
export interface IRequestOptions {
type?: string;
url?: string;
user?: string;
password?: string;
headers?: any;
headers?: IHeaders;
timeout?: number;
data?: string;
followRedirects?: number;
}
export interface IRequestContext {
// req: http.ClientRequest;
// res: http.ClientResponse;
res: {
headers: { [n: string]: string };
headers: IHeaders;
statusCode?: number;
};
stream: VSBufferReadableStream;

View file

@ -0,0 +1,51 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc';
import { Event } from 'vs/base/common/event';
import { IRequestService, IRequestOptions, IRequestContext, IHeaders } from 'vs/platform/request/common/request';
import { CancellationToken } from 'vs/base/common/cancellation';
import { VSBuffer, bufferToStream, streamToBuffer } from 'vs/base/common/buffer';
type RequestResponse = [
{
headers: IHeaders;
statusCode?: number;
},
VSBuffer
];
export class RequestChannel implements IServerChannel {
constructor(private readonly service: IRequestService) { }
listen(context: any, event: string): Event<any> {
throw new Error('Invalid listen');
}
call(context: any, command: string, args?: any): Promise<any> {
switch (command) {
case 'request': return this.service.request(args[0], CancellationToken.None)
.then(async ({ res, stream }) => {
const buffer = await streamToBuffer(stream);
return <RequestResponse>[{ statusCode: res.statusCode, headers: res.headers }, buffer];
});
}
throw new Error('Invalid call');
}
}
export class RequestChannelClient {
_serviceBrand: any;
constructor(private readonly channel: IChannel) { }
async request(options: IRequestOptions, token: CancellationToken): Promise<IRequestContext> {
const [res, buffer] = await this.channel.call<RequestResponse>('request', [options]);
return { res, stream: bufferToStream(buffer) };
}
}

View file

@ -12,7 +12,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
import { onUnexpectedError } from 'vs/base/common/errors';
import { ILogService } from 'vs/platform/log/common/log';
import { generateUuid } from 'vs/base/common/uuid';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
type Key = string;
type Value = string;

View file

@ -38,3 +38,9 @@ export interface ITelemetryService {
isOptedIn: boolean;
}
// Keys
export const instanceStorageKey = 'telemetry.instanceId';
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';

View file

@ -19,6 +19,7 @@ export interface ITelemetryServiceConfig {
appender: ITelemetryAppender;
commonProperties?: Promise<{ [name: string]: any }>;
piiPaths?: string[];
trueMachineId?: string;
}
export class TelemetryService implements ITelemetryService {
@ -74,6 +75,15 @@ export class TelemetryService implements ITelemetryService {
}
*/
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId });
if (config.trueMachineId) {
/* __GDPR__
"machineIdDisambiguation" : {
"correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
}
*/
this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
}
});
}
}

View file

@ -5,11 +5,7 @@
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
export const instanceStorageKey = 'telemetry.instanceId';
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> {
const result = await resolveCommonProperties(commit, version, machineId, installSourcePath);

View file

@ -1084,8 +1084,11 @@ declare module 'vscode' {
/**
* Implement to handle when the terminal is ready to start firing events.
*
* @param initialDimensions The dimensions of the terminal, this will be undefined if the
* terminal panel has not been opened before this is called.
*/
start?(): void;
start?(initialDimensions: TerminalDimensions | undefined): void;
}
//#endregion

View file

@ -88,7 +88,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
const disposables = new DisposableStore();
const webview = this._webviewService.createWebview({
const webview = this._webviewService.createWebview('' + handle, {
enableFindWidget: false,
allowSvgs: false,
extension: { id: extensionId, location: URI.revive(extensionLocation) }

View file

@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig } from 'vs/workbench/api/common/extHost.protocol';
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal';
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
@ -48,7 +48,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(proxy => this._onTerminalRequestVirtualProcess(proxy)));
this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(e => this._onTerminalRequestVirtualProcess(e)));
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
@ -244,12 +244,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
return;
}
const ready = this._terminalProcessesReady[request.proxy.terminalId];
const proxy = request.proxy;
const ready = this._terminalProcessesReady[proxy.terminalId];
if (ready) {
ready(request.proxy);
delete this._terminalProcessesReady[request.proxy.terminalId];
ready(proxy);
delete this._terminalProcessesReady[proxy.terminalId];
} else {
this._terminalProcesses[request.proxy.terminalId] = Promise.resolve(request.proxy);
this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy);
}
const shellLaunchConfigDto: ShellLaunchConfigDto = {
name: request.shellLaunchConfig.name,
@ -258,16 +259,17 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
cwd: request.shellLaunchConfig.cwd,
env: request.shellLaunchConfig.env
};
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
request.proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(request.proxy.terminalId));
request.proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(request.proxy.terminalId));
request.proxy.onRequestLatency(() => this._onRequestLatency(request.proxy.terminalId));
this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows));
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId));
proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId));
}
private _onTerminalRequestVirtualProcess(proxy: ITerminalProcessExtHostProxy): void {
private _onTerminalRequestVirtualProcess(request: ITerminalVirtualProcessRequest): void {
const proxy = request.proxy;
const ready = this._terminalProcessesReady[proxy.terminalId];
if (!ready) {
this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy);
@ -278,6 +280,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
// Note that onReisze is not being listened to here as it needs to fire when max dimensions
// change, excluding the dimension override
const initialDimensions: ITerminalDimensionsDto | undefined = request.cols && request.rows ? {
columns: request.cols,
rows: request.rows
} : undefined;
this._proxy.$startVirtualProcess(proxy.terminalId, initialDimensions);
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));

View file

@ -93,7 +93,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
}
const webview = this._webviewEditorService.createWebview(this.getInternalWebviewId(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
location: URI.revive(extensionLocation),
id: extensionId
}, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>;
@ -212,7 +212,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
this._revivers.delete(viewType);
}
private getInternalWebviewId(viewType: string): string {
private getInternalWebviewViewType(viewType: string): string {
return `mainThreadWebview-${viewType}`;
}

View file

@ -1135,6 +1135,11 @@ export interface IShellAndArgsDto {
args: string[] | string | undefined;
}
export interface ITerminalDimensionsDto {
columns: number;
rows: number;
}
export interface ExtHostTerminalServiceShape {
$acceptTerminalClosed(id: number): void;
$acceptTerminalOpened(id: number, name: string): void;
@ -1146,6 +1151,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
$startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void;
$acceptProcessInput(id: number, data: string): void;
$acceptProcessResize(id: number, cols: number, rows: number): void;
$acceptProcessShutdown(id: number, immediate: boolean): void;

View file

@ -40,7 +40,7 @@ export class ExtHostWebview implements vscode.Webview {
}
public get cspSource(): string {
return this._initData.webviewCspSource;
return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
}
public get html(): string {

View file

@ -10,7 +10,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import * as platform from 'vs/base/common/platform';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { Event, Emitter } from 'vs/base/common/event';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ILogService } from 'vs/platform/log/common/log';
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
@ -329,10 +329,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options.name);
const p = new ExtHostVirtualProcess(options.virtualProcess);
terminal.createVirtualProcess().then(() => {
this._setupExtHostProcessListeners(terminal._id, p);
p.startSendingEvents();
});
terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p));
this._terminals.push(terminal);
return terminal;
}
@ -344,7 +341,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
}
const p = new ExtHostVirtualProcess(virtualProcess);
this._setupExtHostProcessListeners(id, p);
p.startSendingEvents();
}
public createTerminalRenderer(name: string): vscode.TerminalRenderer {
@ -585,6 +581,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
}
public $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void {
(this._terminalProcesses[id] as ExtHostVirtualProcess).startSendingEvents(initialDimensions);
}
private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
@ -779,7 +779,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
return Promise.resolve(0);
}
startSendingEvents(): void {
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
// Flush all buffered events
this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data));
this._queuedEvents = [];
@ -798,7 +798,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
}
if (this._virtualProcess.start) {
this._virtualProcess.start();
this._virtualProcess.start(initialDimensions);
}
}
}

View file

@ -40,6 +40,9 @@ import { joinPath } from 'vs/base/common/resources';
import { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
import { IRequestService } from 'vs/platform/request/common/request';
import { RequestService } from 'vs/workbench/services/request/browser/requestService';
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
class CodeRendererMain extends Disposable {
@ -155,12 +158,14 @@ class CodeRendererMain extends Disposable {
}
}
// User Data Provider
if (userDataProvider) {
fileService.registerProvider(Schemas.userData, userDataProvider);
if (!userDataProvider) {
userDataProvider = this._register(new InMemoryUserDataProvider());
}
const services = await Promise.all([
// User Data Provider
fileService.registerProvider(Schemas.userData, userDataProvider);
const [configurationService, storageService] = await Promise.all([
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
// Workspace
@ -181,7 +186,10 @@ class CodeRendererMain extends Disposable {
})
]);
return { serviceCollection, logService, storageService: services[1] };
// Request Service
serviceCollection.set(IRequestService, new RequestService(this.configuration.requestHandler, remoteAgentService, configurationService, logService));
return { serviceCollection, logService, storageService };
}
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise<BrowserStorageService> {

View file

@ -11,9 +11,8 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
// tslint:disable-next-line: import-patterns no-standalone-editor
import { IDownloadService } from 'vs/platform/download/common/download';
import { CancellationToken } from 'vs/base/common/cancellation';
import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IPager } from 'vs/base/common/paging';
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
@ -29,7 +28,6 @@ import { ITunnelService } from 'vs/platform/remote/common/tunnel';
import { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug';
import { IRemoteConsoleLog } from 'vs/base/common/console';
// tslint:disable-next-line: import-patterns
// tslint:disable-next-line: import-patterns
import { IExtensionsWorkbenchService, IExtension as IExtension2 } from 'vs/workbench/contrib/extensions/common/extensions';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
@ -41,6 +39,8 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { IProcessEnvironment } from 'vs/base/common/platform';
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
// tslint:disable-next-line: import-patterns
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
//#region Download
@ -58,74 +58,6 @@ registerSingleton(IDownloadService, SimpleDownloadService, true);
//#endregion
//#region Extension Gallery
export class SimpleExtensionGalleryService implements IExtensionGalleryService {
_serviceBrand: any;
isEnabled(): boolean {
return false;
}
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(arg1: any, arg2?: any): Promise<IPager<IGalleryExtension>> {
// @ts-ignore
return Promise.resolve(undefined);
}
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string> {
// @ts-ignore
return Promise.resolve(undefined);
}
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void> {
return Promise.resolve(undefined);
}
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
// @ts-ignore
return Promise.resolve(undefined);
}
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest> {
// @ts-ignore
return Promise.resolve(undefined);
}
getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
// @ts-ignore
return Promise.resolve(undefined);
}
getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise<ITranslation> {
// @ts-ignore
return Promise.resolve(undefined);
}
getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise<IGalleryExtensionVersion[]> {
// @ts-ignore
return Promise.resolve(undefined);
}
getExtensionsReport(): Promise<IReportedExtension[]> {
// @ts-ignore
return Promise.resolve(undefined);
}
// @ts-ignore
getCompatibleExtension(extension: IGalleryExtension): Promise<IGalleryExtension>;
getCompatibleExtension(id: IExtensionIdentifier, version?: string): Promise<IGalleryExtension>;
getCompatibleExtension(id: any, version?: any) {
return Promise.resolve(undefined);
}
}
registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, true);
//#endregion
//#endregion IExtensionsWorkbenchService
export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService {
_serviceBrand: any;
@ -1066,3 +998,34 @@ class SimpleTunnelService implements ITunnelService {
registerSingleton(ITunnelService, SimpleTunnelService);
//#endregion
//#region experiments
class ExperimentService implements IExperimentService {
_serviceBrand: any;
async getExperimentById(id: string): Promise<IExperiment> {
return {
enabled: false,
id: '',
state: ExperimentState.NoRun
};
}
async getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]> {
return [];
}
async getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]> {
return [];
}
markAsCompleted(experimentId: string): void { }
onExperimentEnabled: Event<IExperiment> = Event.None;
}
registerSingleton(IExperimentService, ExperimentService);
//#endregion

View file

@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { Event } from 'vs/base/common/event';
export const enum ExperimentState {
Evaluating,
NoRun,
Run,
Complete
}
export interface IExperimentAction {
type: ExperimentActionType;
properties: any;
}
export enum ExperimentActionType {
Custom = 'Custom',
Prompt = 'Prompt',
AddToRecommendations = 'AddToRecommendations',
ExtensionSearchResults = 'ExtensionSearchResults'
}
export type LocalizedPromptText = { [locale: string]: string; };
export interface IExperimentActionPromptProperties {
promptText: string | LocalizedPromptText;
commands: IExperimentActionPromptCommand[];
}
export interface IExperimentActionPromptCommand {
text: string | { [key: string]: string };
externalLink?: string;
curatedExtensionsKey?: string;
curatedExtensionsList?: string[];
}
export interface IExperiment {
id: string;
enabled: boolean;
state: ExperimentState;
action?: IExperimentAction;
}
export interface IExperimentService {
_serviceBrand: any;
getExperimentById(id: string): Promise<IExperiment>;
getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]>;
getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]>;
markAsCompleted(experimentId: string): void;
onExperimentEnabled: Event<IExperiment>;
}
export const IExperimentService = createDecorator<IExperimentService>('experimentService');

View file

@ -3,12 +3,9 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import product from 'vs/platform/product/node/product';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
@ -21,8 +18,9 @@ import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/co
import { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats';
import { CancellationToken } from 'vs/base/common/cancellation';
import { distinct } from 'vs/base/common/arrays';
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
import { ExperimentState, IExperimentAction, IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties } from 'vs/workbench/contrib/experiments/common/experimentService';
import { IProductService } from 'vs/platform/product/common/product';
interface IExperimentStorageState {
enabled: boolean;
@ -31,13 +29,6 @@ interface IExperimentStorageState {
lastEditedDate?: string;
}
export const enum ExperimentState {
Evaluating,
NoRun,
Run,
Complete
}
interface IRawExperiment {
id: string;
enabled?: boolean;
@ -64,51 +55,6 @@ interface IRawExperiment {
action?: IExperimentAction;
}
interface IExperimentAction {
type: ExperimentActionType;
properties: any;
}
export enum ExperimentActionType {
Custom = 'Custom',
Prompt = 'Prompt',
AddToRecommendations = 'AddToRecommendations',
ExtensionSearchResults = 'ExtensionSearchResults'
}
export type LocalizedPromptText = { [locale: string]: string; };
export interface IExperimentActionPromptProperties {
promptText: string | LocalizedPromptText;
commands: IExperimentActionPromptCommand[];
}
export interface IExperimentActionPromptCommand {
text: string | { [key: string]: string };
externalLink?: string;
curatedExtensionsKey?: string;
curatedExtensionsList?: string[];
}
export interface IExperiment {
id: string;
enabled: boolean;
state: ExperimentState;
action?: IExperimentAction;
}
export interface IExperimentService {
_serviceBrand: any;
getExperimentById(id: string): Promise<IExperiment>;
getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]>;
getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]>;
markAsCompleted(experimentId: string): void;
onExperimentEnabled: Event<IExperiment>;
}
export const IExperimentService = createDecorator<IExperimentService>('experimentService');
export class ExperimentService extends Disposable implements IExperimentService {
_serviceBrand: any;
private _experiments: IExperiment[] = [];
@ -127,7 +73,8 @@ export class ExperimentService extends Disposable implements IExperimentService
@ITelemetryService private readonly telemetryService: ITelemetryService,
@ILifecycleService private readonly lifecycleService: ILifecycleService,
@IRequestService private readonly requestService: IRequestService,
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService
) {
super();
@ -171,10 +118,10 @@ export class ExperimentService extends Disposable implements IExperimentService
}
protected getExperiments(): Promise<IRawExperiment[]> {
if (!product.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
return Promise.resolve([]);
}
return this.requestService.request({ type: 'GET', url: product.experimentsUrl }, CancellationToken.None).then(context => {
return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => {
if (context.res.statusCode !== 200) {
return Promise.resolve(null);
}

View file

@ -5,7 +5,7 @@
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';

View file

@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { IExperimentService, ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';

View file

@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/
import * as assert from 'assert';
import { ExperimentService, ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/common/experimentService';
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
@ -17,7 +18,7 @@ import { Emitter } from 'vs/base/common/event';
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
import { URLService } from 'vs/platform/url/common/urlService';
import { IURLService } from 'vs/platform/url/common/url';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
@ -25,7 +26,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { assign } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType } from 'vs/platform/extensions/common/extensions';

View file

@ -13,7 +13,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt';
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/common/experimentService';
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';

View file

@ -25,11 +25,10 @@ import { IExtensionManifest, IKeyBinding, IView, IViewContainer, ExtensionType }
import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions';
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { EditorOptions } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IOpenerService } from 'vs/platform/opener/common/opener';
@ -44,7 +43,7 @@ import { assign } from 'vs/base/common/objects';
import { INotificationService } from 'vs/platform/notification/common/notification';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionsTree, ExtensionData } from 'vs/workbench/contrib/extensions/browser/extensionsViewer';
import { ShowCurrentReleaseNotesAction } from 'vs/workbench/contrib/update/electron-browser/update';
import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update';
import { KeybindingParser } from 'vs/base/common/keybindingParser';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@ -52,6 +51,7 @@ import { getDefaultValue } from 'vs/platform/configuration/common/configurationR
import { isUndefined } from 'vs/base/common/types';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { URI } from 'vs/base/common/uri';
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
function renderBody(body: string): string {
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://');
@ -194,8 +194,8 @@ export class ExtensionEditor extends BaseEditor {
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
@IStorageService storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService,
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
@IWebviewService private readonly webviewService: IWebviewService
) {
super(ExtensionEditor.ID, telemetryService, themeService, storageService);
this.extensionReadme = null;
@ -490,8 +490,8 @@ export class ExtensionEditor extends BaseEditor {
}
showFind(): void {
if (this.activeElement instanceof WebviewElement) {
this.activeElement.showFind();
if (this.activeElement && (<Webview>this.activeElement).showFind) {
(<Webview>this.activeElement).showFind();
}
}
@ -537,7 +537,7 @@ export class ExtensionEditor extends BaseEditor {
.then(renderBody)
.then(removeEmbeddedSVGs)
.then(body => {
const webviewElement = this.instantiationService.createInstance(WebviewElement,
const webviewElement = this.webviewService.createWebview('extensionEditor',
{
enableFindWidget: true,
},
@ -558,7 +558,7 @@ export class ExtensionEditor extends BaseEditor {
return;
}
// Whitelist supported schemes for links
if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesAction.ID)) {
if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesActionId)) {
this.openerService.open(link);
}
}, null, this.contentDisposables));

View file

@ -13,9 +13,9 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
import { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { INotificationService } from 'vs/platform/notification/common/notification';

View file

@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
import { timeout, Delayer } from 'vs/base/common/async';
import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
import { Event as EventOf, Emitter } from 'vs/base/common/event';
import { IAction } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
@ -23,10 +23,10 @@ import {
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
} from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews';
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@ -339,7 +339,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private extensionsBox: HTMLElement;
private primaryActions: IAction[];
private secondaryActions: IAction[] | null;
private disposables: IDisposable[] = [];
private readonly searchViewletState: MementoObject;
constructor(
@ -374,14 +373,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables));
this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this));
this.searchViewletState = this.getMemento(StorageScope.WORKSPACE);
this.extensionManagementService.getInstalled(ExtensionType.User).then(result => {
this.hasInstalledExtensionsContextKey.set(result.length > 0);
});
this.configurationService.onDidChangeConfiguration(e => {
this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
this.secondaryActions = null;
this.updateTitleArea();
@ -389,7 +388,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) {
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
}
}, this, this.disposables);
}, this));
}
create(parent: HTMLElement): void {
@ -401,7 +400,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
const placeholder = localize('searchExtensions', "Search Extensions in Marketplace");
const searchValue = this.searchViewletState['query.value'] ? this.searchViewletState['query.value'] : '';
this.searchBox = this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, {
this.searchBox = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, {
triggerCharacters: ['@'],
sortKey: (item: string) => {
if (item.indexOf(':') === -1) { return 'a'; }
@ -410,24 +409,22 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
else { return 'd'; }
},
provideResults: (query: string) => Query.suggestions(query)
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue });
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue }));
if (this.searchBox.getValue()) {
this.triggerSearch();
}
this.disposables.push(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
this.disposables.push(this.searchBox);
this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
const _searchChange = new Emitter<string>();
this.onSearchChange = _searchChange.event;
this.searchBox.onInputDidChange(() => {
this._register(this.searchBox.onInputDidChange(() => {
this.triggerSearch();
_searchChange.fire(this.searchBox.getValue());
}, this, this.disposables);
}, this));
this.searchBox.onShouldFocusResults(() => this.focusListView(), this, this.disposables);
this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this));
this._register(this.onDidChangeVisibility(visible => {
if (visible) {
@ -614,52 +611,39 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.notificationService.error(err);
}
dispose(): void {
this.disposables = dispose(this.disposables);
super.dispose();
}
}
export class StatusUpdater implements IWorkbenchContribution {
export class StatusUpdater extends Disposable implements IWorkbenchContribution {
private disposables: IDisposable[];
private badgeHandle: IDisposable;
private readonly badgeHandle = this._register(new MutableDisposable());
constructor(
@IActivityService private readonly activityService: IActivityService,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
) {
extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables);
super();
this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this));
}
private onServiceChange(): void {
dispose(this.badgeHandle);
this.badgeHandle.clear();
if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) {
this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge');
this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge');
return;
}
const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0);
if (outdated > 0) {
const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n));
this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge');
this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge');
}
}
dispose(): void {
this.disposables = dispose(this.disposables);
dispose(this.badgeHandle);
}
}
export class MaliciousExtensionChecker implements IWorkbenchContribution {
private disposables: IDisposable[];
constructor(
@IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService,
@IWindowService private readonly windowService: IWindowService,
@ -704,8 +688,4 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution {
}).then(() => undefined);
}, err => this.logService.error(err));
}
dispose(): void {
this.disposables = dispose(this.disposables);
}
}

View file

@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { append, $, toggleClass } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/electron-browser/extensionsList';
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList';
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
import { Query } from '../common/extensionQuery';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
@ -27,14 +27,14 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { distinct, coalesce } from 'vs/base/common/arrays';
import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService';
import { alert } from 'vs/base/browser/ui/aria/aria';
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';

View file

@ -4,14 +4,14 @@
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/extensionsWidgets';
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
import { Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions';
import { append, $, addClass } from 'vs/base/browser/dom';
import * as platform from 'vs/base/common/platform';
import { localize } from 'vs/nls';
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ILabelService } from 'vs/platform/label/common/label';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
@ -196,7 +196,7 @@ export class TooltipWidget extends ExtensionWidget {
export class RecommendationWidget extends ExtensionWidget {
private element?: HTMLElement;
private disposables: IDisposable[] = [];
private readonly disposables = this._register(new DisposableStore());
private _tooltip: string;
get tooltip(): string { return this._tooltip; }
@ -227,7 +227,7 @@ export class RecommendationWidget extends ExtensionWidget {
this.parent.removeChild(this.element);
}
this.element = undefined;
this.disposables = dispose(this.disposables);
this.disposables.clear();
}
render(): void {
@ -256,8 +256,7 @@ export class RecommendationWidget extends ExtensionWidget {
export class RemoteBadgeWidget extends ExtensionWidget {
private remoteBadge: RemoteBadge | null;
private disposables: IDisposable[] = [];
private readonly remoteBadge = this._register(new MutableDisposable<RemoteBadge>());
private element: HTMLElement;
@ -274,12 +273,10 @@ export class RemoteBadgeWidget extends ExtensionWidget {
}
private clear(): void {
if (this.remoteBadge) {
this.element.removeChild(this.remoteBadge.element);
this.remoteBadge.dispose();
if (this.remoteBadge.value) {
this.element.removeChild(this.remoteBadge.value.element);
}
this.remoteBadge = null;
this.disposables = dispose(this.disposables);
this.remoteBadge.clear();
}
render(): void {
@ -288,17 +285,10 @@ export class RemoteBadgeWidget extends ExtensionWidget {
return;
}
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
append(this.element, this.remoteBadge.element);
this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
append(this.element, this.remoteBadge.value.element);
}
}
dispose(): void {
if (this.remoteBadge) {
this.remoteBadge.dispose();
}
super.dispose();
}
}
class RemoteBadge extends Disposable {

View file

Before

Width:  |  Height:  |  Size: 474 B

After

Width:  |  Height:  |  Size: 474 B

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