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: [], hot-exit: [],
html: [], html: [],
install-update: [], install-update: [],
integrated-terminal: [ Tyriar ], integrated-terminal: [],
integration-test: [], integration-test: [],
intellisense-config: [], intellisense-config: [],
issue-reporter: [ RMacfarlane ], issue-reporter: [ RMacfarlane ],

4
.gitignore vendored
View file

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

View file

@ -30,7 +30,7 @@ node build/azure-pipelines/common/publish.js \
../vscode-server-darwin.zip ../vscode-server-darwin.zip
# publish hockeyapp symbols # 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 # upload configuration
yarn gulp upload-vscode-configuration yarn gulp upload-vscode-configuration

View file

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

View file

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

View file

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

View file

@ -16,7 +16,7 @@ steps:
- task: DownloadPipelineArtifact@0 - task: DownloadPipelineArtifact@0
displayName: 'Download Pipeline Artifact' displayName: 'Download Pipeline Artifact'
inputs: inputs:
artifactName: snap-$(VSCODE_ARCH) artifactName: snap-x64
targetPath: .build/linux/snap-tarball targetPath: .build/linux/snap-tarball
- script: | - script: |
@ -31,14 +31,13 @@ steps:
# Define variables # Define variables
REPO="$(pwd)" REPO="$(pwd)"
ARCH="$(VSCODE_ARCH)" SNAP_ROOT="$REPO/.build/linux/snap/x64"
SNAP_ROOT="$REPO/.build/linux/snap/$ARCH"
# Install build dependencies # Install build dependencies
(cd build && yarn) (cd build && yarn)
# Unpack snap tarball artifact, in order to preserve file perms # 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) (cd .build/linux && tar -xzf $SNAP_TARBALL_PATH)
# Create snap package # Create snap package
@ -52,4 +51,4 @@ steps:
# Publish snap package # Publish snap package
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ 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 - job: Compile
pool: pool:
vmImage: 'Ubuntu-16.04' vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: vscode-x64 container: vscode-x64
steps: steps:
- template: product-compile.yml - template: product-compile.yml
- job: Windows - job: Windows
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true'))
timeoutInMinutes: 120
pool: pool:
vmImage: VS2017-Win2016 vmImage: VS2017-Win2016
variables: variables:
@ -30,7 +27,6 @@ jobs:
- job: Windows32 - job: Windows32
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true'))
timeoutInMinutes: 120
pool: pool:
vmImage: VS2017-Win2016 vmImage: VS2017-Win2016
variables: variables:
@ -42,11 +38,8 @@ jobs:
- job: Linux - job: Linux
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
timeoutInMinutes: 120
pool: pool:
vmImage: 'Ubuntu-16.04' vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: vscode-x64 container: vscode-x64
dependsOn: dependsOn:
- Compile - Compile
@ -55,11 +48,8 @@ jobs:
- job: LinuxSnap - job: LinuxSnap
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
timeoutInMinutes: 120
pool: pool:
vmImage: 'Ubuntu-16.04' vmImage: 'Ubuntu-16.04'
variables:
VSCODE_ARCH: x64
container: snapcraft container: snapcraft
dependsOn: Linux dependsOn: Linux
steps: steps:
@ -67,7 +57,6 @@ jobs:
- job: LinuxArmhf - job: LinuxArmhf
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool: pool:
vmImage: 'Ubuntu-16.04' vmImage: 'Ubuntu-16.04'
variables: variables:
@ -79,7 +68,6 @@ jobs:
- job: LinuxAlpine - job: LinuxAlpine
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
timeoutInMinutes: 120
pool: pool:
vmImage: 'Ubuntu-16.04' vmImage: 'Ubuntu-16.04'
variables: variables:
@ -89,9 +77,19 @@ jobs:
steps: steps:
- template: linux/product-build-linux-multiarch.yml - 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 - job: macOS
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true')) condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true'))
timeoutInMinutes: 120
pool: pool:
vmImage: macOS 10.13 vmImage: macOS 10.13
dependsOn: dependsOn:

View file

@ -6,8 +6,8 @@ steps:
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1 - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs: inputs:
keyfile: '.build/commit' keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode' vstsFeed: 'npm-vscode'
platformIndependent: true platformIndependent: true
alias: 'Compilation' alias: 'Compilation'
@ -31,8 +31,6 @@ steps:
- script: | - script: |
set -e set -e
export npm_config_arch="$(VSCODE_ARCH)"
cat << EOF > ~/.netrc cat << EOF > ~/.netrc
machine github.com machine github.com
login vscode login vscode
@ -105,14 +103,21 @@ steps:
yarn gulp compile-extensions-build yarn gulp compile-extensions-build
yarn gulp minify-vscode yarn gulp minify-vscode
yarn gulp minify-vscode-reh yarn gulp minify-vscode-reh
yarn gulp minify-vscode-web yarn gulp minify-vscode-reh-web
displayName: Compile displayName: Compile
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true')) 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 - task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
inputs: inputs:
keyfile: '.build/commit' keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode' vstsFeed: 'npm-vscode'
platformIndependent: true platformIndependent: true
alias: 'Compilation' 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 - task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
inputs: inputs:
keyfile: '.build/commit' keyfile: 'build/.cachesalt, .build/commit'
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min' targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
vstsFeed: 'npm-vscode' vstsFeed: 'npm-vscode'
platformIndependent: true platformIndependent: true
alias: 'Compilation' alias: 'Compilation'
@ -98,7 +98,7 @@ steps:
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" $env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" } 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-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" } exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }
displayName: Build 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-armhf-min', noop);
gulp.task('vscode-reh-linux-alpine-min', noop); gulp.task('vscode-reh-linux-alpine-min', noop);
gulp.task('vscode-web-win32-ia32-min', noop); gulp.task('vscode-reh-web-win32-ia32-min', noop);
gulp.task('vscode-web-win32-x64-min', noop); gulp.task('vscode-reh-web-win32-x64-min', noop);
gulp.task('vscode-web-darwin-min', noop); gulp.task('vscode-reh-web-darwin-min', noop);
gulp.task('vscode-web-linux-x64-min', noop); gulp.task('vscode-reh-web-linux-x64-min', noop);
gulp.task('vscode-web-linux-alpine-min', noop); gulp.task('vscode-reh-web-linux-alpine-min', noop);
function getNodeVersion() { function getNodeVersion() {
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); 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-amd.js',
'out-build/bootstrap-window.js', 'out-build/bootstrap-window.js',
'out-build/paths.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/code/browser/**/*.html',
'out-build/vs/base/common/performance.js', 'out-build/vs/base/common/performance.js',
'out-build/vs/base/node/languagePacks.js', 'out-build/vs/base/node/languagePacks.js',
@ -86,12 +86,6 @@ const vscodeResources = [
'!**/test/**' '!**/test/**'
]; ];
const BUNDLED_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
const optimizeVSCodeTask = task.define('optimize-vscode', task.series( const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
util.rimraf('out-vscode'), util.rimraf('out-vscode'),
common.optimizeTask({ common.optimizeTask({
@ -99,7 +93,6 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
entryPoints: vscodeEntryPoints, entryPoints: vscodeEntryPoints,
resources: vscodeResources, resources: vscodeResources,
loaderConfig: common.loaderConfig(nodeModules), loaderConfig: common.loaderConfig(nodeModules),
header: BUNDLED_FILE_HEADER,
out: 'out-vscode', out: 'out-vscode',
bundleInfo: undefined bundleInfo: undefined
}) })
@ -265,16 +258,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
const src = gulp.src(out + '/**', { base: '.' }) const src = gulp.src(out + '/**', { base: '.' })
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); })) .pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); }))
.pipe(util.setExecutableBit(['**/*.sh'])) .pipe(util.setExecutableBit(['**/*.sh']));
.pipe(filter(['**', '!**/*.js.map']));
const root = path.resolve(path.join(__dirname, '..'));
const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true }); 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; let version = packageJson.version;
// @ts-ignore JSON checking: quality is optional
const quality = product.quality; const quality = product.quality;
if (quality && quality !== 'stable') { 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 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 dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]));
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true }) 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 // This task is only run for the MacOS build
const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => { const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => {
return new Promise((resolve, reject) => { 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) { data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8'); }), '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); this.emit('data', data);
})); }));
}); });
@ -195,20 +189,21 @@ function packageLocalExtensionsStream() {
}) })
.filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)); .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) return fromLocal(extension.path)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
})) });
.pipe(util2.setExecutableBit(['**/*.sh'])) return es.merge(nodeModules, ...localExtensions)
.pipe(filter(['**', '!**/*.js.map'])); .pipe(util2.setExecutableBit(['**/*.sh']));
} }
exports.packageLocalExtensionsStream = packageLocalExtensionsStream; exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
function packageMarketplaceExtensionsStream() { function packageMarketplaceExtensionsStream() {
return es.merge(builtInExtensions.map(extension => { const extensions = builtInExtensions.map(extension => {
return fromMarketplace(extension.name, extension.version, extension.metadata) return fromMarketplace(extension.name, extension.version, extension.metadata)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
})) });
.pipe(util2.setExecutableBit(['**/*.sh'])) return es.merge(extensions)
.pipe(filter(['**', '!**/*.js.map'])); .pipe(util2.setExecutableBit(['**/*.sh']));
} }
exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream; exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;

View file

@ -130,12 +130,6 @@ function fromLocalWebpack(extensionPath: string): Stream {
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`; return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
}), 'utf8'); }), '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); this.emit('data', data);
})); }));
}); });
@ -237,22 +231,22 @@ export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream {
.filter(({ name }) => excludedExtensions.indexOf(name) === -1) .filter(({ name }) => excludedExtensions.indexOf(name) === -1)
.filter(({ name }) => builtInExtensions.every(b => b.name !== name)); .filter(({ name }) => builtInExtensions.every(b => b.name !== name));
return es.merge( const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
gulp.src('extensions/node_modules/**', { base: '.' }), const localExtensions = localExtensionDescriptions.map(extension => {
...localExtensionDescriptions.map(extension => { return fromLocal(extension.path)
return fromLocal(extension.path) .pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); });
})
) return es.merge(nodeModules, ...localExtensions)
.pipe(util2.setExecutableBit(['**/*.sh'])) .pipe(util2.setExecutableBit(['**/*.sh']));
.pipe(filter(['**', '!**/*.js.map']));
} }
export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream { export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream {
return es.merge(builtInExtensions.map(extension => { const extensions = builtInExtensions.map(extension => {
return fromMarketplace(extension.name, extension.version, extension.metadata) return fromMarketplace(extension.name, extension.version, extension.metadata)
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`)); .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); return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
})); }));
} }
const DEFAULT_FILE_HEADER = [
'/*!--------------------------------------------------------',
' * Copyright (C) Microsoft Corporation. All rights reserved.',
' *--------------------------------------------------------*/'
].join('\n');
function optimizeTask(opts) { function optimizeTask(opts) {
const src = opts.src; const src = opts.src;
const entryPoints = opts.entryPoints; const entryPoints = opts.entryPoints;
const resources = opts.resources; const resources = opts.resources;
const loaderConfig = opts.loaderConfig; 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 bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
const out = opts.out; const out = opts.out;
return function () { return function () {

View file

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

View file

@ -6,6 +6,6 @@
"private": true, "private": true,
"license": "MIT", "license": "MIT",
"devDependencies": { "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'); // node modules used by vscode server
yarnInstall('remote/web'); // node modules used by vscode web
const allExtensionFolders = fs.readdirSync('extensions'); const allExtensionFolders = fs.readdirSync('extensions');
const extensions = allExtensionFolders.filter(e => { const extensions = allExtensionFolders.filter(e => {
try { try {

View file

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

View file

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

View file

@ -6,3 +6,4 @@ extension.webpack.config.js
CONTRIBUTING.md CONTRIBUTING.md
cgmanifest.json cgmanifest.json
yarn.lock 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/** src/**
tsconfig.json tsconfig.json
cgmanifest.json cgmanifest.json
.vscode

View file

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

View file

@ -270,27 +270,6 @@ suite('window namespace tests', () => {
window.createTerminal({ name: 'c', virtualProcess }); 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) => { test('should fire Terminal.onData on write', (done) => {
const reg1 = window.onDidOpenTerminal(term => { const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term); equal(terminal, term);
@ -313,6 +292,26 @@ suite('window namespace tests', () => {
const terminal = window.createTerminal({ name: 'foo', virtualProcess }); 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) => { test('should respect dimension overrides', (done) => {
const reg1 = window.onDidOpenTerminal(term => { const reg1 = window.onDidOpenTerminal(term => {
equal(terminal, term); equal(terminal, term);

View file

@ -1 +0,0 @@
node_modules

View file

@ -1,7 +1,7 @@
{ {
"name": "code-oss-dev", "name": "code-oss-dev",
"version": "1.37.0", "version": "1.37.0",
"distro": "4d4ca170652edf13efd5916e009bdc9c0d4d1103", "distro": "a76f8ddb784119243aa004071cea17c5a74b1e60",
"author": { "author": {
"name": "Microsoft Corporation" "name": "Microsoft Corporation"
}, },
@ -29,7 +29,6 @@
}, },
"dependencies": { "dependencies": {
"applicationinsights": "1.0.8", "applicationinsights": "1.0.8",
"getmac": "1.4.1",
"graceful-fs": "4.1.11", "graceful-fs": "4.1.11",
"http-proxy-agent": "^2.1.0", "http-proxy-agent": "^2.1.0",
"https-proxy-agent": "^2.2.1", "https-proxy-agent": "^2.2.1",
@ -157,4 +156,4 @@
"windows-mutex": "0.2.1", "windows-mutex": "0.2.1",
"windows-process-tree": "0.2.4" "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 { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
import { Action } from 'vs/base/common/actions'; import { Action } from 'vs/base/common/actions';
import { mnemonicButtonLabel } from 'vs/base/common/labels'; 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 { export interface IDialogOptions {
cancelId?: number; cancelId?: number;
@ -97,9 +97,9 @@ export class Dialog extends Disposable {
clearNode(this.buttonsContainer); clearNode(this.buttonsContainer);
let focusedButton = 0; 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); 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); button.label = mnemonicButtonLabel(buttonMap[index].label, true);
this._register(button.onDidClick(e => { this._register(button.onDidClick(e => {
@ -115,18 +115,16 @@ export class Dialog extends Disposable {
} }
let eventHandled = false; let eventHandled = false;
if (this.buttonGroup) { if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) { focusedButton = focusedButton + buttonGroup.buttons.length - 1;
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1; focusedButton = focusedButton % buttonGroup.buttons.length;
focusedButton = focusedButton % this.buttonGroup.buttons.length; buttonGroup.buttons[focusedButton].focus();
this.buttonGroup.buttons[focusedButton].focus(); eventHandled = true;
eventHandled = true; } else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) { focusedButton++;
focusedButton++; focusedButton = focusedButton % buttonGroup.buttons.length;
focusedButton = focusedButton % this.buttonGroup.buttons.length; buttonGroup.buttons[focusedButton].focus();
this.buttonGroup.buttons[focusedButton].focus(); eventHandled = true;
eventHandled = true;
}
} }
if (eventHandled) { if (eventHandled) {
@ -192,7 +190,11 @@ export class Dialog extends Disposable {
show(this.element); show(this.element);
// Focus first 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 }); buttonMap.push({ label: button, index: index });
}); });
if (isMacintosh) { // macOS/linux: reverse button order
if (isMacintosh || isLinux) {
if (cancelId !== undefined) { if (cancelId !== undefined) {
const cancelButton = buttonMap.splice(cancelId, 1)[0]; const cancelButton = buttonMap.splice(cancelId, 1)[0];
buttonMap.reverse(); 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) return (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)
|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9) || (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); || (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE);
} }

View file

@ -212,7 +212,13 @@ export class Sash extends Disposable {
return; 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) { for (const iframe of iframes) {
iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash 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); dispose(disposables);
const iframes = getElementsByTagName('iframe');
for (const iframe of iframes) { for (const iframe of iframes) {
iframe.style.pointerEvents = 'auto'; iframe.style.pointerEvents = 'auto';
} }

View file

@ -41,6 +41,10 @@
position: relative; 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 { .monaco-split-view2.vertical > .split-view-container > .split-view-view {
width: 100%; width: 100%;
} }

View file

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

View file

@ -17,5 +17,5 @@
} }
.hc-black .monaco-toolbar .action-label.toolbar-toggle-more { .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 * as uuid from 'vs/base/common/uuid';
import { networkInterfaces } from 'os'; import { networkInterfaces } from 'os';
import { TernarySearchTree } from 'vs/base/common/map'; 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/ // 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 // 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>; let machineId: Promise<string>;
export function getMachineId(): Promise<string> { export async function getMachineId(): Promise<string> {
return machineId || (machineId = getMacMachineId() if (!machineId) {
.then(id => id || uuid.generateUuid())); // fallback, generate a UUID machineId = (async () => {
const id = await getMacMachineId();
return id || uuid.generateUuid(); // fallback, generate a UUID
})();
}
return machineId;
} }
function getMacMachineId(): Promise<string> { async function getMacMachineId(): Promise<string | undefined> {
return new Promise<string>(resolve => { try {
Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => { const crypto = await import('crypto');
try { const macAddress = await getMac();
getmac.getMac((error, macAddress) => { return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
if (!error) { } catch (err) {
resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex')); errors.onUnexpectedError(err);
} else { return undefined;
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);
});
});
} }

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. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as assert from 'assert'; import * as assert from 'assert';
import * as getmac from 'getmac';
import { getMachineId } from 'vs/base/node/id'; import { getMachineId } from 'vs/base/node/id';
import { getMac } from 'vs/base/node/macAddress';
suite('ID', () => { suite('ID', () => {
@ -16,9 +16,7 @@ suite('ID', () => {
}); });
test('getMac', () => { test('getMac', () => {
return new Promise<string>((resolve, reject) => { return getMac().then(macAddress => {
getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress));
}).then(macAddress => {
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${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 { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; 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 { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
import { IRequestService } from 'vs/platform/request/common/request'; 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 { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider'; import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
import { Schemas } from 'vs/base/common/network'; 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 { export interface ISharedProcessConfiguration {
readonly machineId: string; readonly machineId: string;
@ -114,6 +116,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
services.set(IConfigurationService, configurationService); services.set(IConfigurationService, configurationService);
services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IRequestService, new SyncDescriptor(RequestService));
services.set(IDownloadService, new SyncDescriptor(DownloadService)); services.set(IDownloadService, new SyncDescriptor(DownloadService));
services.set(IProductService, new SyncDescriptor(ProductService));
const mainProcessService = new MainProcessService(server, mainRouter); const mainProcessService = new MainProcessService(server, mainRouter);
services.set(IMainProcessService, mainProcessService); services.set(IMainProcessService, mainProcessService);

View file

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

View file

@ -21,10 +21,12 @@ import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/worksp
import { IBackupMainService } from 'vs/platform/backup/common/backup'; import { IBackupMainService } from 'vs/platform/backup/common/backup';
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
import * as perf from 'vs/base/common/performance'; 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 { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
import { endsWith } from 'vs/base/common/strings'; import { endsWith } from 'vs/base/common/strings';
import { RunOnceScheduler } from 'vs/base/common/async'; 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; const RUN_TEXTMATE_IN_WORKER = false;
@ -76,6 +78,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
config: IWindowCreationOptions, config: IWindowCreationOptions,
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@IFileService private readonly fileService: IFileService,
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IThemeMainService private readonly themeMainService: IThemeMainService, @IThemeMainService private readonly themeMainService: IThemeMainService,
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
@ -307,7 +310,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
private handleMarketplaceRequests(): void { private handleMarketplaceRequests(): void {
// Resolve marketplace headers // Resolve marketplace headers
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.environmentService); this.marketplaceHeadersPromise = resolveMarketplaceHeaders(pkg.version, this.environmentService, this.fileService);
// Inject headers when requests are incoming // Inject headers when requests are incoming
const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*']; 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.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); 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) { if (isWindows) {
// Setup Windows mutex
try { try {
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
const mutex = new WindowsMutex(product.win32MutexName); const mutex = new WindowsMutex(product.win32MutexName);
once(this.lifecycleService.onWillShutdown)(() => mutex.release()); once(this.lifecycleService.onWillShutdown)(() => mutex.release());
} catch (e) { } catch (e) {
this.logService.error(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 { EnvironmentService } from 'vs/platform/environment/node/environmentService';
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService'; 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 { IFileService } from 'vs/platform/files/common/files';
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider'; import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
import { DisposableStore } from 'vs/base/common/lifecycle'; 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 notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", 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(ILogService, logService);
services.set(IConfigurationService, configurationService); services.set(IConfigurationService, configurationService);
services.set(IStateService, new SyncDescriptor(StateService)); services.set(IStateService, new SyncDescriptor(StateService));
services.set(IProductService, new SyncDescriptor(ProductService));
// Files // Files
const fileService = new FileService(logService); 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); 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); 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> { public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise<void> {
let actions: CodeActionSet;
try {
actions = await codeActions;
} catch (e) {
onUnexpectedError(e);
return;
}
this._codeActionWidget.show(actions, at); 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 { Position } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range'; import { IRange, Range } from 'vs/editor/common/core/range';
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; 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 { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';
import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector'; import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel'; 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 hoverElement = $('div.hover-row.status-bar');
const disposables = new DisposableStore(); const disposables = new DisposableStore();
const actionsElement = dom.append(hoverElement, $('div.actions')); 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) { if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
disposables.add(this.renderAction(actionsElement, { disposables.add(this.renderAction(actionsElement, {
label: nls.localize('peek problem', "Peek Problem"), 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; this.renderDisposable.value = disposables;
return hoverElement; return hoverElement;
} }
private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> { private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> {
const noAction: CodeAction = { return createCancelablePromise(cancellationToken => {
title: nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), return getCodeActions(
kind: CodeActionKind.QuickFix.value,
};
return createCancelablePromise(async (cancellationToken): Promise<CodeActionSet> => {
const result = await getCodeActions(
this._editor.getModel()!, this._editor.getModel()!,
new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),
{ type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, { type: 'manual', filter: { kind: CodeActionKind.QuickFix } },
cancellationToken); 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. * 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 { 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 { 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'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IPager } from 'vs/base/common/paging'; import { IPager } from 'vs/base/common/paging';
import { IRequestService, IRequestOptions, IRequestContext, asJson, asText } from 'vs/platform/request/common/request'; import { IRequestService, IRequestOptions, IRequestContext, asJson, asText } from 'vs/platform/request/common/request';
import pkg from 'vs/platform/product/node/package'; import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
import product from 'vs/platform/product/node/product';
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; 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 { generateUuid, isUUID } from 'vs/base/common/uuid';
import { values } from 'vs/base/common/map'; import { values } from 'vs/base/common/map';
import { CancellationToken } from 'vs/base/common/cancellation'; 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 { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
import { IFileService } from 'vs/platform/files/common/files'; import { IFileService } from 'vs/platform/files/common/files';
import { URI } from 'vs/base/common/uri'; 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 { interface IRawGalleryExtensionFile {
assetType: string; assetType: string;
@ -339,11 +337,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
@IEnvironmentService private readonly environmentService: IEnvironmentService, @IEnvironmentService private readonly environmentService: IEnvironmentService,
@ITelemetryService private readonly telemetryService: ITelemetryService, @ITelemetryService private readonly telemetryService: ITelemetryService,
@IFileService private readonly fileService: IFileService, @IFileService private readonly fileService: IFileService,
@IProductService private readonly productService: IProductService,
) { ) {
const config = product.extensionsGallery; const config = productService.extensionsGallery;
this.extensionsGalleryUrl = config && config.serviceUrl; this.extensionsGalleryUrl = config && config.serviceUrl;
this.extensionsControlUrl = config && config.controlUrl; this.extensionsControlUrl = config && config.controlUrl;
this.commonHeadersPromise = resolveMarketplaceHeaders(this.environmentService); this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService);
} }
private api(path = ''): string { private api(path = ''): string {
@ -356,7 +355,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise<IGalleryExtension | null> { getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise<IGalleryExtension | null> {
const extension: IGalleryExtension | null = isIExtensionIdentifier(arg1) ? null : arg1; 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); return Promise.resolve(extension);
} }
const { id, uuid } = extension ? extension.identifier : <IExtensionIdentifier>arg1; 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]; const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
if (versionAsset) { if (versionAsset) {
const extension = toExtension(rawExtension, versionAsset, 0, query); 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; 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); this.logService.trace('ExtensionGalleryService#download', extension.identifier.id);
const zipPath = path.join(tmpdir(), generateUuid()); const zip = joinPath(location, generateUuid());
const data = getGalleryExtensionTelemetryData(extension); const data = getGalleryExtensionTelemetryData(extension);
const startTime = new Date().getTime(); const startTime = new Date().getTime();
/* __GDPR__ /* __GDPR__
@ -557,9 +556,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
} : extension.assets.download; } : extension.assets.download;
return this.getAsset(downloadAsset) 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(() => log(new Date().getTime() - startTime))
.then(() => zipPath); .then(() => zip);
} }
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> { getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
@ -615,7 +614,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => { return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
if (galleryExtensions.length) { if (galleryExtensions.length) {
if (compatible) { 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 .then(versions => versions
.filter(v => !!v) .filter(v => !!v)
.map(v => ({ version: v!.version, date: v!.lastUpdated }))); .map(v => ({ version: v!.version, date: v!.lastUpdated })));
@ -701,7 +700,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
if (!engine) { if (!engine) {
return null; return null;
} }
if (isEngineValid(engine)) { if (isEngineValid(engine, this.productService.version)) {
return Promise.resolve(version); return Promise.resolve(version);
} }
} }
@ -733,7 +732,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
const version = versions[0]; const version = versions[0];
return this.getEngine(version) return this.getEngine(version)
.then(engine => { .then(engine => {
if (!isEngineValid(engine)) { if (!isEngineValid(engine, this.productService.version)) {
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1)); 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; }> { export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService): Promise<{ [key: string]: string; }> {
const marketplaceMachineIdFile = path.join(environmentService.userDataPath, 'machineid'); const marketplaceMachineIdFile = joinPath(URI.file(environmentService.userDataPath), 'machineid');
return readFile(marketplaceMachineIdFile, 'utf8') let uuid: string | null = null;
.then<string | null>(contents => isUUID(contents) ? contents : null, () => null /* error reading ID file */)
.then(uuid => { try {
if (!uuid) { const contents = await fileService.readFile(marketplaceMachineIdFile);
uuid = generateUuid(); const value = contents.value.toString();
try { uuid = isUUID(value) ? value : null;
writeFileSync(marketplaceMachineIdFile, uuid); } catch (e) {
} catch (error) { uuid = null;
//noop }
}
} if (!uuid) {
return { uuid = generateUuid();
'X-Market-Client-Id': `VSCode ${pkg.version}`, try {
'User-Agent': `VSCode ${pkg.version}`, await fileService.writeFile(marketplaceMachineIdFile, VSBuffer.fromString(uuid));
'X-Market-User-Id': 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; isEnabled(): boolean;
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>; query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
query(options: IQueryOptions, 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>; reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>; getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null>; 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 { ExtensionsLifecycle } from 'vs/platform/extensionManagement/node/extensionLifecycle';
import { toErrorMessage } from 'vs/base/common/errorMessage'; import { toErrorMessage } from 'vs/base/common/errorMessage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; 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 { tmpdir } from 'os';
import { generateUuid } from 'vs/base/common/uuid'; import { generateUuid } from 'vs/base/common/uuid';
import { IDownloadService } from 'vs/platform/download/common/download'; import { IDownloadService } from 'vs/platform/download/common/download';
@ -197,7 +197,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
.then(manifest => { .then(manifest => {
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) }; const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
let operation: InstallOperation = InstallOperation.Install; 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))); 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); 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); 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( .then(
zipPath => { zip => {
const zipPath = zip.fsPath;
this.logService.info('Downloaded extension:', extension.identifier.id, zipPath); this.logService.info('Downloaded extension:', extension.identifier.id, zipPath);
return getManifest(zipPath) return getManifest(zipPath)
.then( .then(

View file

@ -10,15 +10,32 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
import { getRandomTestPath } from 'vs/base/test/node/testUtils'; import { getRandomTestPath } from 'vs/base/test/node/testUtils';
import { join } from 'vs/base/common/path'; import { join } from 'vs/base/common/path';
import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs'; 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 { 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', () => { suite('Extension Gallery Service', () => {
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'extensiongalleryservice'); const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'extensiongalleryservice');
const marketplaceHome = join(parentDir, 'Marketplace'); const marketplaceHome = join(parentDir, 'Marketplace');
let fileService: IFileService;
let disposables: DisposableStore;
setup(done => { 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. // Delete any existing backups completely and then re-create it.
rimraf(marketplaceHome, RimRafMode.MOVE).then(() => { rimraf(marketplaceHome, RimRafMode.MOVE).then(() => {
mkdirp(marketplaceHome).then(() => { mkdirp(marketplaceHome).then(() => {
@ -28,6 +45,7 @@ suite('Extension Gallery Service', () => {
}); });
teardown(done => { teardown(done => {
disposables.clear();
rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done); rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done);
}); });
@ -35,10 +53,10 @@ suite('Extension Gallery Service', () => {
const args = ['--user-data-dir', marketplaceHome]; const args = ['--user-data-dir', marketplaceHome];
const environmentService = new EnvironmentService(parseArgs(args), process.execPath); 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'])); 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']); 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 * as nls from 'vs/nls';
import pkg from 'vs/platform/product/node/package';
export interface IParsedVersion { export interface IParsedVersion {
hasCaret: boolean; hasCaret: boolean;
@ -222,9 +221,9 @@ export function isValidExtensionVersion(version: string, extensionDesc: IReduced
return isVersionValid(version, extensionDesc.engines.vscode, notices); 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 // 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 { 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. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as assert from 'assert'; 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', () => { suite('Extension Version Validator', () => {

View file

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

View file

@ -33,4 +33,10 @@ export class ProductService implements IProductService {
get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; } get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; }
get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; } 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 const IRequestService = createDecorator<IRequestService>('requestService');
export interface IHeaders {
[header: string]: string;
}
export interface IRequestOptions { export interface IRequestOptions {
type?: string; type?: string;
url?: string; url?: string;
user?: string; user?: string;
password?: string; password?: string;
headers?: any; headers?: IHeaders;
timeout?: number; timeout?: number;
data?: string; data?: string;
followRedirects?: number; followRedirects?: number;
} }
export interface IRequestContext { export interface IRequestContext {
// req: http.ClientRequest;
// res: http.ClientResponse;
res: { res: {
headers: { [n: string]: string }; headers: IHeaders;
statusCode?: number; statusCode?: number;
}; };
stream: VSBufferReadableStream; 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 { onUnexpectedError } from 'vs/base/common/errors';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { generateUuid } from 'vs/base/common/uuid'; 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 Key = string;
type Value = string; type Value = string;

View file

@ -38,3 +38,9 @@ export interface ITelemetryService {
isOptedIn: boolean; 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; appender: ITelemetryAppender;
commonProperties?: Promise<{ [name: string]: any }>; commonProperties?: Promise<{ [name: string]: any }>;
piiPaths?: string[]; piiPaths?: string[];
trueMachineId?: string;
} }
export class TelemetryService implements ITelemetryService { export class TelemetryService implements ITelemetryService {
@ -74,6 +75,15 @@ export class TelemetryService implements ITelemetryService {
} }
*/ */
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId }); 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 { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties'; import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
export const instanceStorageKey = 'telemetry.instanceId';
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { 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); 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. * 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 //#endregion

View file

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

View file

@ -4,8 +4,8 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; 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 { 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 } from 'vs/workbench/api/common/extHost.protocol'; 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 { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch'; 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.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); 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.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed))); this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
@ -244,12 +244,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
return; return;
} }
const ready = this._terminalProcessesReady[request.proxy.terminalId]; const proxy = request.proxy;
const ready = this._terminalProcessesReady[proxy.terminalId];
if (ready) { if (ready) {
ready(request.proxy); ready(proxy);
delete this._terminalProcessesReady[request.proxy.terminalId]; delete this._terminalProcessesReady[proxy.terminalId];
} else { } else {
this._terminalProcesses[request.proxy.terminalId] = Promise.resolve(request.proxy); this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy);
} }
const shellLaunchConfigDto: ShellLaunchConfigDto = { const shellLaunchConfigDto: ShellLaunchConfigDto = {
name: request.shellLaunchConfig.name, name: request.shellLaunchConfig.name,
@ -258,16 +259,17 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
cwd: request.shellLaunchConfig.cwd, cwd: request.shellLaunchConfig.cwd,
env: request.shellLaunchConfig.env env: request.shellLaunchConfig.env
}; };
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data)); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows)); proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows));
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
request.proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(request.proxy.terminalId)); proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
request.proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(request.proxy.terminalId)); proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId));
request.proxy.onRequestLatency(() => this._onRequestLatency(request.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]; const ready = this._terminalProcessesReady[proxy.terminalId];
if (!ready) { if (!ready) {
this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy); 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 // Note that onReisze is not being listened to here as it needs to fire when max dimensions
// change, excluding the dimension override // 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.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId)); 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); 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), location: URI.revive(extensionLocation),
id: extensionId id: extensionId
}, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>; }, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>;
@ -212,7 +212,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
this._revivers.delete(viewType); this._revivers.delete(viewType);
} }
private getInternalWebviewId(viewType: string): string { private getInternalWebviewViewType(viewType: string): string {
return `mainThreadWebview-${viewType}`; return `mainThreadWebview-${viewType}`;
} }

View file

@ -1135,6 +1135,11 @@ export interface IShellAndArgsDto {
args: string[] | string | undefined; args: string[] | string | undefined;
} }
export interface ITerminalDimensionsDto {
columns: number;
rows: number;
}
export interface ExtHostTerminalServiceShape { export interface ExtHostTerminalServiceShape {
$acceptTerminalClosed(id: number): void; $acceptTerminalClosed(id: number): void;
$acceptTerminalOpened(id: number, name: string): void; $acceptTerminalOpened(id: number, name: string): void;
@ -1146,6 +1151,7 @@ export interface ExtHostTerminalServiceShape {
$acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void;
$acceptTerminalMaximumDimensions(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; $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; $acceptProcessInput(id: number, data: string): void;
$acceptProcessResize(id: number, cols: number, rows: number): void; $acceptProcessResize(id: number, cols: number, rows: number): void;
$acceptProcessShutdown(id: number, immediate: boolean): void; $acceptProcessShutdown(id: number, immediate: boolean): void;

View file

@ -40,7 +40,7 @@ export class ExtHostWebview implements vscode.Webview {
} }
public get cspSource(): string { public get cspSource(): string {
return this._initData.webviewCspSource; return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
} }
public get html(): string { 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 platform from 'vs/base/common/platform';
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
import { Event, Emitter } from 'vs/base/common/event'; 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 { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
import { ILogService } from 'vs/platform/log/common/log'; import { ILogService } from 'vs/platform/log/common/log';
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; 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 { public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options.name); const terminal = new ExtHostTerminal(this._proxy, options.name);
const p = new ExtHostVirtualProcess(options.virtualProcess); const p = new ExtHostVirtualProcess(options.virtualProcess);
terminal.createVirtualProcess().then(() => { terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p));
this._setupExtHostProcessListeners(terminal._id, p);
p.startSendingEvents();
});
this._terminals.push(terminal); this._terminals.push(terminal);
return terminal; return terminal;
} }
@ -344,7 +341,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
} }
const p = new ExtHostVirtualProcess(virtualProcess); const p = new ExtHostVirtualProcess(virtualProcess);
this._setupExtHostProcessListeners(id, p); this._setupExtHostProcessListeners(id, p);
p.startSendingEvents();
} }
public createTerminalRenderer(name: string): vscode.TerminalRenderer { 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)); 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 { private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd)); p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title)); p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
@ -779,7 +779,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
return Promise.resolve(0); return Promise.resolve(0);
} }
startSendingEvents(): void { startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
// Flush all buffered events // Flush all buffered events
this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data)); this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data));
this._queuedEvents = []; this._queuedEvents = [];
@ -798,7 +798,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
} }
if (this._virtualProcess.start) { 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 { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService'; 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 { class CodeRendererMain extends Disposable {
@ -155,12 +158,14 @@ class CodeRendererMain extends Disposable {
} }
} }
// User Data Provider if (!userDataProvider) {
if (userDataProvider) { userDataProvider = this._register(new InMemoryUserDataProvider());
fileService.registerProvider(Schemas.userData, userDataProvider);
} }
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 => { this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
// Workspace // 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> { 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 // tslint:disable-next-line: import-patterns no-standalone-editor
import { IDownloadService } from 'vs/platform/download/common/download'; import { IDownloadService } from 'vs/platform/download/common/download';
import { CancellationToken } from 'vs/base/common/cancellation'; 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 { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
import { IPager } from 'vs/base/common/paging'; import { ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log'; 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 { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug';
import { IRemoteConsoleLog } from 'vs/base/common/console'; import { IRemoteConsoleLog } from 'vs/base/common/console';
// tslint:disable-next-line: import-patterns // 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 { IExtensionsWorkbenchService, IExtension as IExtension2 } from 'vs/workbench/contrib/extensions/common/extensions';
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { addDisposableListener, EventType } from 'vs/base/browser/dom'; 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 { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { IProcessEnvironment } from 'vs/base/common/platform'; import { IProcessEnvironment } from 'vs/base/common/platform';
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage'; 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 //#region Download
@ -58,74 +58,6 @@ registerSingleton(IDownloadService, SimpleDownloadService, true);
//#endregion //#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 //#endregion IExtensionsWorkbenchService
export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService { export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService {
_serviceBrand: any; _serviceBrand: any;
@ -1066,3 +998,34 @@ class SimpleTunnelService implements ITunnelService {
registerSingleton(ITunnelService, SimpleTunnelService); registerSingleton(ITunnelService, SimpleTunnelService);
//#endregion //#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. * 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 { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; 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 { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; 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 { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { distinct } from 'vs/base/common/arrays'; import { distinct } from 'vs/base/common/arrays';
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
import { ExtensionType } from 'vs/platform/extensions/common/extensions'; 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 { interface IExperimentStorageState {
enabled: boolean; enabled: boolean;
@ -31,13 +29,6 @@ interface IExperimentStorageState {
lastEditedDate?: string; lastEditedDate?: string;
} }
export const enum ExperimentState {
Evaluating,
NoRun,
Run,
Complete
}
interface IRawExperiment { interface IRawExperiment {
id: string; id: string;
enabled?: boolean; enabled?: boolean;
@ -64,51 +55,6 @@ interface IRawExperiment {
action?: IExperimentAction; 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 { export class ExperimentService extends Disposable implements IExperimentService {
_serviceBrand: any; _serviceBrand: any;
private _experiments: IExperiment[] = []; private _experiments: IExperiment[] = [];
@ -127,7 +73,8 @@ export class ExperimentService extends Disposable implements IExperimentService
@ITelemetryService private readonly telemetryService: ITelemetryService, @ITelemetryService private readonly telemetryService: ITelemetryService,
@ILifecycleService private readonly lifecycleService: ILifecycleService, @ILifecycleService private readonly lifecycleService: ILifecycleService,
@IRequestService private readonly requestService: IRequestService, @IRequestService private readonly requestService: IRequestService,
@IConfigurationService private readonly configurationService: IConfigurationService @IConfigurationService private readonly configurationService: IConfigurationService,
@IProductService private readonly productService: IProductService
) { ) {
super(); super();
@ -171,10 +118,10 @@ export class ExperimentService extends Disposable implements IExperimentService
} }
protected getExperiments(): Promise<IRawExperiment[]> { 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 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) { if (context.res.statusCode !== 200) {
return Promise.resolve(null); return Promise.resolve(null);
} }

View file

@ -5,7 +5,7 @@
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions'; import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions';

View file

@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; 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 { Registry } from 'vs/platform/registry/common/platform';
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';

View file

@ -4,7 +4,8 @@
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import * as assert from 'assert'; 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 { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices'; 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 { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
import { URLService } from 'vs/platform/url/common/urlService'; import { URLService } from 'vs/platform/url/common/urlService';
import { IURLService } from 'vs/platform/url/common/url'; 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 { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService'; 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 { assign } from 'vs/base/common/objects';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; 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 { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
import { ExtensionType } from 'vs/platform/extensions/common/extensions'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt'; 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 { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices'; 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 { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions'; 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 { EditorOptions } from 'vs/workbench/common/editor';
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; 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 { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
import { IOpenerService } from 'vs/platform/opener/common/opener'; 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 { INotificationService } from 'vs/platform/notification/common/notification';
import { CancellationToken } from 'vs/base/common/cancellation'; import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionsTree, ExtensionData } from 'vs/workbench/contrib/extensions/browser/extensionsViewer'; 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 { KeybindingParser } from 'vs/base/common/keybindingParser';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; 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 { isUndefined } from 'vs/base/common/types';
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
import { URI } from 'vs/base/common/uri'; import { URI } from 'vs/base/common/uri';
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
function renderBody(body: string): string { function renderBody(body: string): string {
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://'); 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, @IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
@IStorageService storageService: IStorageService, @IStorageService storageService: IStorageService,
@IExtensionService private readonly extensionService: IExtensionService, @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); super(ExtensionEditor.ID, telemetryService, themeService, storageService);
this.extensionReadme = null; this.extensionReadme = null;
@ -490,8 +490,8 @@ export class ExtensionEditor extends BaseEditor {
} }
showFind(): void { showFind(): void {
if (this.activeElement instanceof WebviewElement) { if (this.activeElement && (<Webview>this.activeElement).showFind) {
this.activeElement.showFind(); (<Webview>this.activeElement).showFind();
} }
} }
@ -537,7 +537,7 @@ export class ExtensionEditor extends BaseEditor {
.then(renderBody) .then(renderBody)
.then(removeEmbeddedSVGs) .then(removeEmbeddedSVGs)
.then(body => { .then(body => {
const webviewElement = this.instantiationService.createInstance(WebviewElement, const webviewElement = this.webviewService.createWebview('extensionEditor',
{ {
enableFindWidget: true, enableFindWidget: true,
}, },
@ -558,7 +558,7 @@ export class ExtensionEditor extends BaseEditor {
return; return;
} }
// Whitelist supported schemes for links // 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); this.openerService.open(link);
} }
}, null, this.contentDisposables)); }, 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 { Event } from 'vs/base/common/event';
import { domEvent } from 'vs/base/browser/event'; import { domEvent } from 'vs/base/browser/event';
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions'; 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 { 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 { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { INotificationService } from 'vs/platform/notification/common/notification'; 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 { timeout, Delayer } from 'vs/base/common/async';
import { isPromiseCanceledError } from 'vs/base/common/errors'; import { isPromiseCanceledError } from 'vs/base/common/errors';
import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; 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 { Event as EventOf, Emitter } from 'vs/base/common/event';
import { IAction } from 'vs/base/common/actions'; import { IAction } from 'vs/base/common/actions';
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
@ -23,10 +23,10 @@ import {
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction 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 { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; 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 { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
@ -339,7 +339,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
private extensionsBox: HTMLElement; private extensionsBox: HTMLElement;
private primaryActions: IAction[]; private primaryActions: IAction[];
private secondaryActions: IAction[] | null; private secondaryActions: IAction[] | null;
private disposables: IDisposable[] = [];
private readonly searchViewletState: MementoObject; private readonly searchViewletState: MementoObject;
constructor( constructor(
@ -374,14 +373,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService); this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService); this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey)); 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.searchViewletState = this.getMemento(StorageScope.WORKSPACE);
this.extensionManagementService.getInstalled(ExtensionType.User).then(result => { this.extensionManagementService.getInstalled(ExtensionType.User).then(result => {
this.hasInstalledExtensionsContextKey.set(result.length > 0); this.hasInstalledExtensionsContextKey.set(result.length > 0);
}); });
this.configurationService.onDidChangeConfiguration(e => { this._register(this.configurationService.onDidChangeConfiguration(e => {
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
this.secondaryActions = null; this.secondaryActions = null;
this.updateTitleArea(); this.updateTitleArea();
@ -389,7 +388,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) { if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) {
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey)); this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
} }
}, this, this.disposables); }, this));
} }
create(parent: HTMLElement): void { create(parent: HTMLElement): void {
@ -401,7 +400,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
const placeholder = localize('searchExtensions', "Search Extensions in Marketplace"); const placeholder = localize('searchExtensions', "Search Extensions in Marketplace");
const searchValue = this.searchViewletState['query.value'] ? this.searchViewletState['query.value'] : ''; 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: ['@'], triggerCharacters: ['@'],
sortKey: (item: string) => { sortKey: (item: string) => {
if (item.indexOf(':') === -1) { return 'a'; } if (item.indexOf(':') === -1) { return 'a'; }
@ -410,24 +409,22 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
else { return 'd'; } else { return 'd'; }
}, },
provideResults: (query: string) => Query.suggestions(query) provideResults: (query: string) => Query.suggestions(query)
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue }); }, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue }));
if (this.searchBox.getValue()) { if (this.searchBox.getValue()) {
this.triggerSearch(); this.triggerSearch();
} }
this.disposables.push(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService)); this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
this.disposables.push(this.searchBox);
const _searchChange = new Emitter<string>(); const _searchChange = new Emitter<string>();
this.onSearchChange = _searchChange.event; this.onSearchChange = _searchChange.event;
this.searchBox.onInputDidChange(() => { this._register(this.searchBox.onInputDidChange(() => {
this.triggerSearch(); this.triggerSearch();
_searchChange.fire(this.searchBox.getValue()); _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 => { this._register(this.onDidChangeVisibility(visible => {
if (visible) { if (visible) {
@ -614,52 +611,39 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
this.notificationService.error(err); 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 readonly badgeHandle = this._register(new MutableDisposable());
private badgeHandle: IDisposable;
constructor( constructor(
@IActivityService private readonly activityService: IActivityService, @IActivityService private readonly activityService: IActivityService,
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
) { ) {
extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables); super();
this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this));
} }
private onServiceChange(): void { private onServiceChange(): void {
this.badgeHandle.clear();
dispose(this.badgeHandle);
if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { 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; return;
} }
const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0); const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0);
if (outdated > 0) { if (outdated > 0) {
const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); 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 { export class MaliciousExtensionChecker implements IWorkbenchContribution {
private disposables: IDisposable[];
constructor( constructor(
@IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService, @IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService,
@IWindowService private readonly windowService: IWindowService, @IWindowService private readonly windowService: IWindowService,
@ -704,8 +688,4 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution {
}).then(() => undefined); }).then(() => undefined);
}, err => this.logService.error(err)); }, 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 { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
import { append, $, toggleClass } from 'vs/base/browser/dom'; import { append, $, toggleClass } from 'vs/base/browser/dom';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; 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 { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
import { Query } from '../common/extensionQuery'; import { Query } from '../common/extensionQuery';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; 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 { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; 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 { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { distinct, coalesce } from 'vs/base/common/arrays'; 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 { alert } from 'vs/base/browser/ui/aria/aria';
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list'; import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions';

View file

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