Merge remote-tracking branch 'origin/master' into tyriar/puppeteer
2
.github/classifier.yml
vendored
|
@ -81,7 +81,7 @@
|
|||
hot-exit: [],
|
||||
html: [],
|
||||
install-update: [],
|
||||
integrated-terminal: [ Tyriar ],
|
||||
integrated-terminal: [],
|
||||
integration-test: [],
|
||||
intellisense-config: [],
|
||||
issue-reporter: [ RMacfarlane ],
|
||||
|
|
4
.gitignore
vendored
|
@ -18,9 +18,11 @@ out-vscode-min/
|
|||
out-vscode-reh/
|
||||
out-vscode-reh-min/
|
||||
out-vscode-reh-pkg/
|
||||
out-vscode-reh-web/
|
||||
out-vscode-reh-web-min/
|
||||
out-vscode-reh-web-pkg/
|
||||
out-vscode-web/
|
||||
out-vscode-web-min/
|
||||
out-vscode-web-pkg/
|
||||
src/vs/server
|
||||
resources/server
|
||||
build/node_modules
|
||||
|
|
|
@ -1 +1 @@
|
|||
1
|
||||
2019-07-11T05:47:05.444Z
|
||||
|
|
|
@ -6,8 +6,8 @@ steps:
|
|||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
@ -89,9 +89,7 @@ steps:
|
|||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-darwin-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-web-darwin-min-ci
|
||||
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
|
||||
yarn gulp upload-vscode-sourcemaps
|
||||
yarn gulp vscode-reh-web-darwin-min-ci
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
|
|
|
@ -30,7 +30,7 @@ node build/azure-pipelines/common/publish.js \
|
|||
../vscode-server-darwin.zip
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS"
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" x64 "$VSCODE_HOCKEYAPP_ID_MACOS"
|
||||
|
||||
# upload configuration
|
||||
yarn gulp upload-vscode-configuration
|
||||
|
|
|
@ -6,8 +6,8 @@ steps:
|
|||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
|
|
@ -6,8 +6,8 @@ steps:
|
|||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
@ -34,8 +34,6 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
export npm_config_arch="$(VSCODE_ARCH)"
|
||||
|
||||
cat << EOF > ~/.netrc
|
||||
machine github.com
|
||||
login vscode
|
||||
|
@ -86,22 +84,22 @@ steps:
|
|||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-linux-$VSCODE_ARCH-min-ci
|
||||
yarn gulp vscode-linux-x64-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-reh-linux-$VSCODE_ARCH-min-ci
|
||||
yarn gulp vscode-reh-linux-x64-min-ci
|
||||
VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \
|
||||
yarn gulp vscode-web-linux-$VSCODE_ARCH-min-ci
|
||||
yarn gulp vscode-reh-web-linux-x64-min-ci
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
yarn gulp "electron-$(VSCODE_ARCH)"
|
||||
yarn gulp "electron-x64"
|
||||
|
||||
# xvfb seems to be crashing often, let's make sure it's always up
|
||||
service xvfb start
|
||||
|
||||
DISPLAY=:10 ./scripts/test.sh --build --tfs "Unit Tests"
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-$(VSCODE_ARCH)"
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-linux-x64"
|
||||
displayName: Run unit tests
|
||||
condition: and(succeeded(), eq(variables['VSCODE_STEP_ON_IT'], 'false'))
|
||||
|
||||
|
@ -117,7 +115,7 @@ steps:
|
|||
- task: PublishPipelineArtifact@0
|
||||
displayName: 'Publish Pipeline Artifact'
|
||||
inputs:
|
||||
artifactName: snap-$(VSCODE_ARCH)
|
||||
artifactName: snap-x64
|
||||
targetPath: .build/linux/snap-tarball
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
|
|
|
@ -4,7 +4,7 @@ REPO="$(pwd)"
|
|||
ROOT="$REPO/.."
|
||||
|
||||
# Publish tarball
|
||||
PLATFORM_LINUX="linux-$VSCODE_ARCH"
|
||||
PLATFORM_LINUX="linux-x64"
|
||||
BUILDNAME="VSCode-$PLATFORM_LINUX"
|
||||
BUILD="$ROOT/$BUILDNAME"
|
||||
BUILD_VERSION="$(date +%s)"
|
||||
|
@ -19,24 +19,22 @@ rm -rf $ROOT/code-*.tar.*
|
|||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
|
||||
|
||||
# Publish Remote Extension Host
|
||||
if [[ "$VSCODE_ARCH" != "ia32" ]]; then
|
||||
LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX"
|
||||
SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX"
|
||||
SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz"
|
||||
SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME"
|
||||
LEGACY_SERVER_BUILD_NAME="vscode-reh-$PLATFORM_LINUX"
|
||||
SERVER_BUILD_NAME="vscode-server-$PLATFORM_LINUX"
|
||||
SERVER_TARBALL_FILENAME="vscode-server-$PLATFORM_LINUX.tar.gz"
|
||||
SERVER_TARBALL_PATH="$ROOT/$SERVER_TARBALL_FILENAME"
|
||||
|
||||
rm -rf $ROOT/vscode-server-*.tar.*
|
||||
(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME)
|
||||
rm -rf $ROOT/vscode-server-*.tar.*
|
||||
(cd $ROOT && mv $LEGACY_SERVER_BUILD_NAME $SERVER_BUILD_NAME && tar --owner=0 --group=0 -czf $SERVER_TARBALL_PATH $SERVER_BUILD_NAME)
|
||||
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH"
|
||||
fi
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "server-$PLATFORM_LINUX" archive-unsigned "$SERVER_TARBALL_FILENAME" "$VERSION" true "$SERVER_TARBALL_PATH"
|
||||
|
||||
# Publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "x64" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
||||
|
||||
# Publish DEB
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb"
|
||||
PLATFORM_DEB="linux-deb-$VSCODE_ARCH"
|
||||
yarn gulp "vscode-linux-x64-build-deb"
|
||||
PLATFORM_DEB="linux-deb-x64"
|
||||
DEB_ARCH="amd64"
|
||||
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
|
||||
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
|
||||
|
@ -44,8 +42,8 @@ DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
|
|||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
|
||||
|
||||
# Publish RPM
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm"
|
||||
PLATFORM_RPM="linux-rpm-$VSCODE_ARCH"
|
||||
yarn gulp "vscode-linux-x64-build-rpm"
|
||||
PLATFORM_RPM="linux-rpm-x64"
|
||||
RPM_ARCH="x86_64"
|
||||
RPM_FILENAME="$(ls $REPO/.build/linux/rpm/$RPM_ARCH/ | grep .rpm)"
|
||||
RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
|
||||
|
@ -53,10 +51,10 @@ RPM_PATH="$REPO/.build/linux/rpm/$RPM_ARCH/$RPM_FILENAME"
|
|||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
|
||||
|
||||
# Publish Snap
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-prepare-snap"
|
||||
yarn gulp "vscode-linux-x64-prepare-snap"
|
||||
|
||||
# Pack snap tarball artifact, in order to preserve file perms
|
||||
mkdir -p $REPO/.build/linux/snap-tarball
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$VSCODE_ARCH.tar.gz"
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz"
|
||||
rm -rf $SNAP_TARBALL_PATH
|
||||
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
|
||||
|
|
|
@ -16,7 +16,7 @@ steps:
|
|||
- task: DownloadPipelineArtifact@0
|
||||
displayName: 'Download Pipeline Artifact'
|
||||
inputs:
|
||||
artifactName: snap-$(VSCODE_ARCH)
|
||||
artifactName: snap-x64
|
||||
targetPath: .build/linux/snap-tarball
|
||||
|
||||
- script: |
|
||||
|
@ -31,14 +31,13 @@ steps:
|
|||
|
||||
# Define variables
|
||||
REPO="$(pwd)"
|
||||
ARCH="$(VSCODE_ARCH)"
|
||||
SNAP_ROOT="$REPO/.build/linux/snap/$ARCH"
|
||||
SNAP_ROOT="$REPO/.build/linux/snap/x64"
|
||||
|
||||
# Install build dependencies
|
||||
(cd build && yarn)
|
||||
|
||||
# Unpack snap tarball artifact, in order to preserve file perms
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-$ARCH.tar.gz"
|
||||
SNAP_TARBALL_PATH="$REPO/.build/linux/snap-tarball/snap-x64.tar.gz"
|
||||
(cd .build/linux && tar -xzf $SNAP_TARBALL_PATH)
|
||||
|
||||
# Create snap package
|
||||
|
@ -52,4 +51,4 @@ steps:
|
|||
# Publish snap package
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-$ARCH" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "linux-snap-x64" package "$SNAP_FILENAME" "$VERSION" true "$SNAP_PATH"
|
|
@ -10,15 +10,12 @@ jobs:
|
|||
- job: Compile
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
container: vscode-x64
|
||||
steps:
|
||||
- template: product-compile.yml
|
||||
|
||||
- job: Windows
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32'], 'true'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: VS2017-Win2016
|
||||
variables:
|
||||
|
@ -30,7 +27,6 @@ jobs:
|
|||
|
||||
- job: Windows32
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WIN32_32BIT'], 'true'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: VS2017-Win2016
|
||||
variables:
|
||||
|
@ -42,11 +38,8 @@ jobs:
|
|||
|
||||
- job: Linux
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
container: vscode-x64
|
||||
dependsOn:
|
||||
- Compile
|
||||
|
@ -55,11 +48,8 @@ jobs:
|
|||
|
||||
- job: LinuxSnap
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX'], 'true'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
container: snapcraft
|
||||
dependsOn: Linux
|
||||
steps:
|
||||
|
@ -67,7 +57,6 @@ jobs:
|
|||
|
||||
- job: LinuxArmhf
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
|
@ -79,7 +68,6 @@ jobs:
|
|||
|
||||
- job: LinuxAlpine
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_LINUX_ALPINE'], 'true'), ne(variables['VSCODE_QUALITY'], 'stable'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
|
@ -89,9 +77,19 @@ jobs:
|
|||
steps:
|
||||
- template: linux/product-build-linux-multiarch.yml
|
||||
|
||||
- job: LinuxWeb
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_WEB'], 'true'))
|
||||
pool:
|
||||
vmImage: 'Ubuntu-16.04'
|
||||
variables:
|
||||
VSCODE_ARCH: x64
|
||||
dependsOn:
|
||||
- Compile
|
||||
steps:
|
||||
- template: web/product-build-web.yml
|
||||
|
||||
- job: macOS
|
||||
condition: and(succeeded(), eq(variables['VSCODE_COMPILE_ONLY'], 'false'), eq(variables['VSCODE_BUILD_MACOS'], 'true'))
|
||||
timeoutInMinutes: 120
|
||||
pool:
|
||||
vmImage: macOS 10.13
|
||||
dependsOn:
|
||||
|
|
|
@ -6,8 +6,8 @@ steps:
|
|||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
@ -31,8 +31,6 @@ steps:
|
|||
|
||||
- script: |
|
||||
set -e
|
||||
export npm_config_arch="$(VSCODE_ARCH)"
|
||||
|
||||
cat << EOF > ~/.netrc
|
||||
machine github.com
|
||||
login vscode
|
||||
|
@ -105,14 +103,21 @@ steps:
|
|||
yarn gulp compile-extensions-build
|
||||
yarn gulp minify-vscode
|
||||
yarn gulp minify-vscode-reh
|
||||
yarn gulp minify-vscode-web
|
||||
yarn gulp minify-vscode-reh-web
|
||||
displayName: Compile
|
||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
AZURE_STORAGE_ACCESS_KEY="$(ticino-storage-key)" \
|
||||
node build/azure-pipelines/upload-sourcemaps
|
||||
displayName: Upload sourcemaps
|
||||
condition: and(succeeded(), ne(variables['CacheRestored-Compilation'], 'true'))
|
||||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.SaveCacheV1.SaveCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
|
39
build/azure-pipelines/upload-sourcemaps.js
Normal 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();
|
96
build/azure-pipelines/web/product-build-web.yml
Normal 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
|
15
build/azure-pipelines/web/publish.sh
Executable 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"
|
|
@ -6,8 +6,8 @@ steps:
|
|||
|
||||
- task: 1ESLighthouseEng.PipelineArtifactCaching.RestoreCacheV1.RestoreCache@1
|
||||
inputs:
|
||||
keyfile: '.build/commit'
|
||||
targetfolder: '.build, **/out-build, **/out-vscode-min, **/out-vscode-reh-min, **/out-vscode-web-min'
|
||||
keyfile: 'build/.cachesalt, .build/commit'
|
||||
targetfolder: '.build, out-build, out-vscode-min, out-vscode-reh-min, out-vscode-reh-web-min'
|
||||
vstsFeed: 'npm-vscode'
|
||||
platformIndependent: true
|
||||
alias: 'Compilation'
|
||||
|
@ -98,7 +98,7 @@ steps:
|
|||
$env:VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)"
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-win32-$env:VSCODE_ARCH-min-ci" }
|
||||
exec { yarn gulp "vscode-web-win32-$env:VSCODE_ARCH-min-ci" }
|
||||
exec { yarn gulp "vscode-reh-web-win32-$env:VSCODE_ARCH-min-ci" }
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }
|
||||
displayName: Build
|
||||
|
||||
|
|
|
@ -43,11 +43,11 @@ gulp.task('vscode-reh-linux-x64-min', noop);
|
|||
gulp.task('vscode-reh-linux-armhf-min', noop);
|
||||
gulp.task('vscode-reh-linux-alpine-min', noop);
|
||||
|
||||
gulp.task('vscode-web-win32-ia32-min', noop);
|
||||
gulp.task('vscode-web-win32-x64-min', noop);
|
||||
gulp.task('vscode-web-darwin-min', noop);
|
||||
gulp.task('vscode-web-linux-x64-min', noop);
|
||||
gulp.task('vscode-web-linux-alpine-min', noop);
|
||||
gulp.task('vscode-reh-web-win32-ia32-min', noop);
|
||||
gulp.task('vscode-reh-web-win32-x64-min', noop);
|
||||
gulp.task('vscode-reh-web-darwin-min', noop);
|
||||
gulp.task('vscode-reh-web-linux-x64-min', noop);
|
||||
gulp.task('vscode-reh-web-linux-alpine-min', noop);
|
||||
|
||||
function getNodeVersion() {
|
||||
const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8');
|
||||
|
|
|
@ -63,7 +63,7 @@ const vscodeResources = [
|
|||
'out-build/bootstrap-amd.js',
|
||||
'out-build/bootstrap-window.js',
|
||||
'out-build/paths.js',
|
||||
'out-build/vs/**/*.{svg,png,cur,html}',
|
||||
'out-build/vs/**/*.{svg,png,html}',
|
||||
'!out-build/vs/code/browser/**/*.html',
|
||||
'out-build/vs/base/common/performance.js',
|
||||
'out-build/vs/base/node/languagePacks.js',
|
||||
|
@ -86,12 +86,6 @@ const vscodeResources = [
|
|||
'!**/test/**'
|
||||
];
|
||||
|
||||
const BUNDLED_FILE_HEADER = [
|
||||
'/*!--------------------------------------------------------',
|
||||
' * Copyright (C) Microsoft Corporation. All rights reserved.',
|
||||
' *--------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
|
||||
const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
|
||||
util.rimraf('out-vscode'),
|
||||
common.optimizeTask({
|
||||
|
@ -99,7 +93,6 @@ const optimizeVSCodeTask = task.define('optimize-vscode', task.series(
|
|||
entryPoints: vscodeEntryPoints,
|
||||
resources: vscodeResources,
|
||||
loaderConfig: common.loaderConfig(nodeModules),
|
||||
header: BUNDLED_FILE_HEADER,
|
||||
out: 'out-vscode',
|
||||
bundleInfo: undefined
|
||||
})
|
||||
|
@ -265,16 +258,14 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||
|
||||
const src = gulp.src(out + '/**', { base: '.' })
|
||||
.pipe(rename(function (path) { path.dirname = path.dirname.replace(new RegExp('^' + out), 'out'); }))
|
||||
.pipe(util.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
|
||||
const root = path.resolve(path.join(__dirname, '..'));
|
||||
.pipe(util.setExecutableBit(['**/*.sh']));
|
||||
|
||||
const extensions = gulp.src('.build/extensions/**', { base: '.build', dot: true });
|
||||
const sources = es.merge(src, extensions);
|
||||
|
||||
const sources = es.merge(src, extensions)
|
||||
.pipe(filter(['**', '!**/*.js.map'], { dot: true }));
|
||||
|
||||
let version = packageJson.version;
|
||||
// @ts-ignore JSON checking: quality is optional
|
||||
const quality = product.quality;
|
||||
|
||||
if (quality && quality !== 'stable') {
|
||||
|
@ -309,6 +300,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
|||
|
||||
const telemetry = gulp.src('.build/telemetry/**', { base: '.build/telemetry', dot: true });
|
||||
|
||||
const root = path.resolve(path.join(__dirname, '..'));
|
||||
const dependenciesSrc = _.flatten(productionDependencies.map(d => path.relative(root, d.path)).map(d => [`${d}/**`, `!${d}/**/{test,tests}/**`]));
|
||||
|
||||
const deps = gulp.src(dependenciesSrc, { base: '.', dot: true })
|
||||
|
@ -535,32 +527,6 @@ gulp.task('vscode-translations-import', function () {
|
|||
}));
|
||||
});
|
||||
|
||||
// Sourcemaps
|
||||
|
||||
gulp.task('upload-vscode-sourcemaps', () => {
|
||||
const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only
|
||||
.pipe(es.mapSync(f => {
|
||||
f.path = `${f.base}/core/${f.relative}`;
|
||||
return f;
|
||||
}));
|
||||
|
||||
const extensionsOut = gulp.src(['extensions/**/out/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
|
||||
const extensionsDist = gulp.src(['extensions/**/dist/**/*.map', '!extensions/**/node_modules/**'], { base: '.' });
|
||||
|
||||
return es.merge(vs, extensionsOut, extensionsDist)
|
||||
.pipe(es.through(function (data) {
|
||||
// debug
|
||||
console.log('Uploading Sourcemap', data.relative);
|
||||
this.emit('data', data);
|
||||
}))
|
||||
.pipe(azure.upload({
|
||||
account: process.env.AZURE_STORAGE_ACCOUNT,
|
||||
key: process.env.AZURE_STORAGE_ACCESS_KEY,
|
||||
container: 'sourcemaps',
|
||||
prefix: commit + '/'
|
||||
}));
|
||||
});
|
||||
|
||||
// This task is only run for the MacOS build
|
||||
const generateVSCodeConfigurationTask = task.define('generate-vscode-configuration', () => {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
151
build/gulpfile.vscode.web.js
Normal 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);
|
||||
});
|
|
@ -111,12 +111,6 @@ function fromLocalWebpack(extensionPath) {
|
|||
data.contents = Buffer.from(contents.replace(/\n\/\/# sourceMappingURL=(.*)$/gm, function (_m, g1) {
|
||||
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
|
||||
}), 'utf8');
|
||||
if (/\.js\.map$/.test(data.path)) {
|
||||
if (!fs.existsSync(path.dirname(data.path))) {
|
||||
fs.mkdirSync(path.dirname(data.path));
|
||||
}
|
||||
fs.writeFileSync(data.path, data.contents);
|
||||
}
|
||||
this.emit('data', data);
|
||||
}));
|
||||
});
|
||||
|
@ -195,20 +189,21 @@ function packageLocalExtensionsStream() {
|
|||
})
|
||||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name));
|
||||
return es.merge(gulp.src('extensions/node_modules/**', { base: '.' }), ...localExtensionDescriptions.map(extension => {
|
||||
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
|
||||
const localExtensions = localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
}))
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
});
|
||||
return es.merge(nodeModules, ...localExtensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
exports.packageLocalExtensionsStream = packageLocalExtensionsStream;
|
||||
function packageMarketplaceExtensionsStream() {
|
||||
return es.merge(builtInExtensions.map(extension => {
|
||||
const extensions = builtInExtensions.map(extension => {
|
||||
return fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
}))
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
});
|
||||
return es.merge(extensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
exports.packageMarketplaceExtensionsStream = packageMarketplaceExtensionsStream;
|
||||
|
|
|
@ -130,12 +130,6 @@ function fromLocalWebpack(extensionPath: string): Stream {
|
|||
return `\n//# sourceMappingURL=${sourceMappingURLBase}/extensions/${path.basename(extensionPath)}/${relativeOutputPath}/${g1}`;
|
||||
}), 'utf8');
|
||||
|
||||
if (/\.js\.map$/.test(data.path)) {
|
||||
if (!fs.existsSync(path.dirname(data.path))) {
|
||||
fs.mkdirSync(path.dirname(data.path));
|
||||
}
|
||||
fs.writeFileSync(data.path, data.contents);
|
||||
}
|
||||
this.emit('data', data);
|
||||
}));
|
||||
});
|
||||
|
@ -237,22 +231,22 @@ export function packageLocalExtensionsStream(): NodeJS.ReadWriteStream {
|
|||
.filter(({ name }) => excludedExtensions.indexOf(name) === -1)
|
||||
.filter(({ name }) => builtInExtensions.every(b => b.name !== name));
|
||||
|
||||
return es.merge(
|
||||
gulp.src('extensions/node_modules/**', { base: '.' }),
|
||||
...localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
})
|
||||
)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
const nodeModules = gulp.src('extensions/node_modules/**', { base: '.' });
|
||||
const localExtensions = localExtensionDescriptions.map(extension => {
|
||||
return fromLocal(extension.path)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
});
|
||||
|
||||
return es.merge(nodeModules, ...localExtensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
|
||||
export function packageMarketplaceExtensionsStream(): NodeJS.ReadWriteStream {
|
||||
return es.merge(builtInExtensions.map(extension => {
|
||||
const extensions = builtInExtensions.map(extension => {
|
||||
return fromMarketplace(extension.name, extension.version, extension.metadata)
|
||||
.pipe(rename(p => p.dirname = `extensions/${extension.name}/${p.dirname}`));
|
||||
}))
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']))
|
||||
.pipe(filter(['**', '!**/*.js.map']));
|
||||
});
|
||||
|
||||
return es.merge(extensions)
|
||||
.pipe(util2.setExecutableBit(['**/*.sh']));
|
||||
}
|
||||
|
|
|
@ -111,12 +111,17 @@ function toBundleStream(src, bundledFileHeader, bundles) {
|
|||
return toConcatStream(src, bundledFileHeader, bundle.sources, bundle.dest);
|
||||
}));
|
||||
}
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
'/*!--------------------------------------------------------',
|
||||
' * Copyright (C) Microsoft Corporation. All rights reserved.',
|
||||
' *--------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
function optimizeTask(opts) {
|
||||
const src = opts.src;
|
||||
const entryPoints = opts.entryPoints;
|
||||
const resources = opts.resources;
|
||||
const loaderConfig = opts.loaderConfig;
|
||||
const bundledFileHeader = opts.header;
|
||||
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
|
||||
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
|
||||
const out = opts.out;
|
||||
return function () {
|
||||
|
|
|
@ -154,7 +154,7 @@ export interface IOptimizeTaskOpts {
|
|||
/**
|
||||
* (basically the Copyright treatment)
|
||||
*/
|
||||
header: string;
|
||||
header?: string;
|
||||
/**
|
||||
* (emit bundleInfo.json file)
|
||||
*/
|
||||
|
@ -169,12 +169,18 @@ export interface IOptimizeTaskOpts {
|
|||
languages?: Language[];
|
||||
}
|
||||
|
||||
const DEFAULT_FILE_HEADER = [
|
||||
'/*!--------------------------------------------------------',
|
||||
' * Copyright (C) Microsoft Corporation. All rights reserved.',
|
||||
' *--------------------------------------------------------*/'
|
||||
].join('\n');
|
||||
|
||||
export function optimizeTask(opts: IOptimizeTaskOpts): () => NodeJS.ReadWriteStream {
|
||||
const src = opts.src;
|
||||
const entryPoints = opts.entryPoints;
|
||||
const resources = opts.resources;
|
||||
const loaderConfig = opts.loaderConfig;
|
||||
const bundledFileHeader = opts.header;
|
||||
const bundledFileHeader = opts.header || DEFAULT_FILE_HEADER;
|
||||
const bundleLoader = (typeof opts.bundleLoader === 'undefined' ? true : opts.bundleLoader);
|
||||
const out = opts.out;
|
||||
|
||||
|
|
|
@ -6,6 +6,6 @@
|
|||
"private": true,
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"gulp-watch": "^4.3.9"
|
||||
"gulp-watch": "5.0.1"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ yarnInstall('extensions'); // node modules shared by all extensions
|
|||
|
||||
yarnInstall('remote'); // node modules used by vscode server
|
||||
|
||||
yarnInstall('remote/web'); // node modules used by vscode web
|
||||
|
||||
const allExtensionFolders = fs.readdirSync('extensions');
|
||||
const extensions = allExtensionFolders.filter(e => {
|
||||
try {
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
test/**
|
||||
cgmanifest.json
|
||||
.vscode
|
|
@ -2,4 +2,5 @@ src/**
|
|||
tsconfig.json
|
||||
out/**
|
||||
extension.webpack.config.js
|
||||
yarn.lock
|
||||
yarn.lock
|
||||
.vscode
|
|
@ -6,3 +6,4 @@ extension.webpack.config.js
|
|||
CONTRIBUTING.md
|
||||
cgmanifest.json
|
||||
yarn.lock
|
||||
.vscode
|
|
@ -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
|
||||
}
|
|
@ -4,3 +4,4 @@ out/test/**
|
|||
src/**
|
||||
tsconfig.json
|
||||
cgmanifest.json
|
||||
.vscode
|
|
@ -3,3 +3,4 @@ src/**
|
|||
tsconfig.json
|
||||
extension.webpack.config.js
|
||||
cgmanifest.json
|
||||
.vscode
|
|
@ -270,27 +270,6 @@ suite('window namespace tests', () => {
|
|||
window.createTerminal({ name: 'c', virtualProcess });
|
||||
});
|
||||
|
||||
test('should get dimensions event when shown', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
reg1.dispose();
|
||||
equal(terminal, term);
|
||||
term.show();
|
||||
});
|
||||
const virtualProcess: TerminalVirtualProcess = {
|
||||
onDidWrite: new EventEmitter<string>().event,
|
||||
setDimensions: dimensions => {
|
||||
ok(dimensions.columns > 0);
|
||||
ok(dimensions.rows > 0);
|
||||
const reg2 = window.onDidCloseTerminal(() => {
|
||||
reg2.dispose();
|
||||
done();
|
||||
});
|
||||
terminal.dispose();
|
||||
}
|
||||
};
|
||||
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
|
||||
});
|
||||
|
||||
test('should fire Terminal.onData on write', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
equal(terminal, term);
|
||||
|
@ -313,6 +292,26 @@ suite('window namespace tests', () => {
|
|||
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
|
||||
});
|
||||
|
||||
test('should fire provide dimensions on start as the terminal has been shown', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
equal(terminal, term);
|
||||
reg1.dispose();
|
||||
});
|
||||
const virtualProcess: TerminalVirtualProcess = {
|
||||
onDidWrite: new EventEmitter<string>().event,
|
||||
start: (dimensions) => {
|
||||
ok(dimensions!.columns > 0);
|
||||
ok(dimensions!.rows > 0);
|
||||
const reg3 = window.onDidCloseTerminal(() => {
|
||||
reg3.dispose();
|
||||
done();
|
||||
});
|
||||
terminal.dispose();
|
||||
}
|
||||
};
|
||||
const terminal = window.createTerminal({ name: 'foo', virtualProcess });
|
||||
});
|
||||
|
||||
test('should respect dimension overrides', (done) => {
|
||||
const reg1 = window.onDidOpenTerminal(term => {
|
||||
equal(terminal, term);
|
||||
|
|
1
extensions/yaml/.gitignore
vendored
|
@ -1 +0,0 @@
|
|||
node_modules
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "code-oss-dev",
|
||||
"version": "1.37.0",
|
||||
"distro": "4d4ca170652edf13efd5916e009bdc9c0d4d1103",
|
||||
"distro": "a76f8ddb784119243aa004071cea17c5a74b1e60",
|
||||
"author": {
|
||||
"name": "Microsoft Corporation"
|
||||
},
|
||||
|
@ -29,7 +29,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"applicationinsights": "1.0.8",
|
||||
"getmac": "1.4.1",
|
||||
"graceful-fs": "4.1.11",
|
||||
"http-proxy-agent": "^2.1.0",
|
||||
"https-proxy-agent": "^2.2.1",
|
||||
|
@ -157,4 +156,4 @@
|
|||
"windows-mutex": "0.2.1",
|
||||
"windows-process-tree": "0.2.4"
|
||||
}
|
||||
}
|
||||
}
|
3
remote/web/.yarnrc
Normal file
|
@ -0,0 +1,3 @@
|
|||
disturl "http://nodejs.org/dist"
|
||||
target "10.11.0"
|
||||
runtime "node"
|
11
remote/web/package.json
Normal 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
|
@ -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==
|
|
@ -15,7 +15,7 @@ import { ButtonGroup, IButtonStyles } from 'vs/base/browser/ui/button/button';
|
|||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { Action } from 'vs/base/common/actions';
|
||||
import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
import { isMacintosh, isLinux } from 'vs/base/common/platform';
|
||||
|
||||
export interface IDialogOptions {
|
||||
cancelId?: number;
|
||||
|
@ -97,9 +97,9 @@ export class Dialog extends Disposable {
|
|||
clearNode(this.buttonsContainer);
|
||||
|
||||
let focusedButton = 0;
|
||||
this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true });
|
||||
const buttonGroup = this.buttonGroup = new ButtonGroup(this.buttonsContainer, this.buttons.length, { title: true });
|
||||
const buttonMap = this.rearrangeButtons(this.buttons, this.options.cancelId);
|
||||
this.buttonGroup.buttons.forEach((button, index) => {
|
||||
buttonGroup.buttons.forEach((button, index) => {
|
||||
button.label = mnemonicButtonLabel(buttonMap[index].label, true);
|
||||
|
||||
this._register(button.onDidClick(e => {
|
||||
|
@ -115,18 +115,16 @@ export class Dialog extends Disposable {
|
|||
}
|
||||
|
||||
let eventHandled = false;
|
||||
if (this.buttonGroup) {
|
||||
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
|
||||
focusedButton = focusedButton + this.buttonGroup.buttons.length - 1;
|
||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||
this.buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
|
||||
focusedButton++;
|
||||
focusedButton = focusedButton % this.buttonGroup.buttons.length;
|
||||
this.buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
}
|
||||
if (evt.equals(KeyMod.Shift | KeyCode.Tab) || evt.equals(KeyCode.LeftArrow)) {
|
||||
focusedButton = focusedButton + buttonGroup.buttons.length - 1;
|
||||
focusedButton = focusedButton % buttonGroup.buttons.length;
|
||||
buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
} else if (evt.equals(KeyCode.Tab) || evt.equals(KeyCode.RightArrow)) {
|
||||
focusedButton++;
|
||||
focusedButton = focusedButton % buttonGroup.buttons.length;
|
||||
buttonGroup.buttons[focusedButton].focus();
|
||||
eventHandled = true;
|
||||
}
|
||||
|
||||
if (eventHandled) {
|
||||
|
@ -192,7 +190,11 @@ export class Dialog extends Disposable {
|
|||
show(this.element);
|
||||
|
||||
// Focus first element
|
||||
this.buttonGroup.buttons[focusedButton].focus();
|
||||
buttonMap.forEach((value, index) => {
|
||||
if (value.index === focusedButton) {
|
||||
buttonGroup.buttons[index].focus();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -243,7 +245,8 @@ export class Dialog extends Disposable {
|
|||
buttonMap.push({ label: button, index: index });
|
||||
});
|
||||
|
||||
if (isMacintosh) {
|
||||
// macOS/linux: reverse button order
|
||||
if (isMacintosh || isLinux) {
|
||||
if (cancelId !== undefined) {
|
||||
const cancelButton = buttonMap.splice(cancelId, 1)[0];
|
||||
buttonMap.reverse();
|
||||
|
|
|
@ -329,6 +329,7 @@ export function mightProducePrintableCharacter(event: IKeyboardEvent): boolean {
|
|||
|
||||
return (event.keyCode >= KeyCode.KEY_A && event.keyCode <= KeyCode.KEY_Z)
|
||||
|| (event.keyCode >= KeyCode.KEY_0 && event.keyCode <= KeyCode.KEY_9)
|
||||
|| (event.keyCode >= KeyCode.NUMPAD_0 && event.keyCode <= KeyCode.NUMPAD_9)
|
||||
|| (event.keyCode >= KeyCode.US_SEMICOLON && event.keyCode <= KeyCode.US_QUOTE);
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,13 @@ export class Sash extends Disposable {
|
|||
return;
|
||||
}
|
||||
|
||||
const iframes = getElementsByTagName('iframe');
|
||||
// Select both iframes and webviews; internally Electron nests an iframe
|
||||
// in its <webview> component, but this isn't queryable.
|
||||
const iframes = [
|
||||
...getElementsByTagName('iframe'),
|
||||
...getElementsByTagName('webview'),
|
||||
];
|
||||
|
||||
for (const iframe of iframes) {
|
||||
iframe.style.pointerEvents = 'none'; // disable mouse events on iframes as long as we drag the sash
|
||||
}
|
||||
|
@ -280,7 +286,6 @@ export class Sash extends Disposable {
|
|||
|
||||
dispose(disposables);
|
||||
|
||||
const iframes = getElementsByTagName('iframe');
|
||||
for (const iframe of iframes) {
|
||||
iframe.style.pointerEvents = 'auto';
|
||||
}
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-split-view2 > .split-view-container > .split-view-view:not(.visible) {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.monaco-split-view2.vertical > .split-view-container > .split-view-view {
|
||||
width: 100%;
|
||||
}
|
||||
|
|
|
@ -47,7 +47,9 @@ export interface IView {
|
|||
readonly maximumSize: number;
|
||||
readonly onDidChange: Event<number | undefined>;
|
||||
readonly priority?: LayoutPriority;
|
||||
readonly snap?: boolean;
|
||||
layout(size: number, orientation: Orientation): void;
|
||||
setVisible?(visible: boolean): void;
|
||||
}
|
||||
|
||||
interface ISashEvent {
|
||||
|
@ -57,12 +59,79 @@ interface ISashEvent {
|
|||
alt: boolean;
|
||||
}
|
||||
|
||||
interface IViewItem {
|
||||
view: IView;
|
||||
size: number;
|
||||
container: HTMLElement;
|
||||
disposable: IDisposable;
|
||||
layout(): void;
|
||||
abstract class ViewItem {
|
||||
|
||||
set size(size: number) {
|
||||
this._size = size;
|
||||
}
|
||||
|
||||
get size(): number {
|
||||
return this._size;
|
||||
}
|
||||
|
||||
private cachedSize: number | undefined = undefined;
|
||||
|
||||
get visible(): boolean {
|
||||
return typeof this.cachedSize === 'undefined';
|
||||
}
|
||||
|
||||
set visible(visible: boolean) {
|
||||
if (visible === this.visible) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (visible) {
|
||||
this.size = this.cachedSize!;
|
||||
this.cachedSize = undefined;
|
||||
} else {
|
||||
this.cachedSize = this.size;
|
||||
this.size = 0;
|
||||
}
|
||||
|
||||
dom.toggleClass(this.container, 'visible', visible);
|
||||
|
||||
if (this.view.setVisible) {
|
||||
this.view.setVisible(visible);
|
||||
}
|
||||
}
|
||||
|
||||
get minimumSize(): number { return this.visible ? this.view.minimumSize : 0; }
|
||||
get viewMinimumSize(): number { return this.view.minimumSize; }
|
||||
get maximumSize(): number { return this.visible ? this.view.maximumSize : 0; }
|
||||
get viewMaximumSize(): number { return this.view.maximumSize; }
|
||||
get priority(): LayoutPriority | undefined { return this.view.priority; }
|
||||
get snap(): boolean { return !!this.view.snap; }
|
||||
|
||||
constructor(protected container: HTMLElement, private view: IView, private _size: number, private disposable: IDisposable) {
|
||||
dom.addClass(container, 'visible');
|
||||
}
|
||||
|
||||
abstract layout(): void;
|
||||
|
||||
layoutView(orientation: Orientation): void {
|
||||
this.view.layout(this.size, orientation);
|
||||
}
|
||||
|
||||
dispose(): IView {
|
||||
this.disposable.dispose();
|
||||
return this.view;
|
||||
}
|
||||
}
|
||||
|
||||
class VerticalViewItem extends ViewItem {
|
||||
|
||||
layout(): void {
|
||||
this.container.style.height = `${this.size}px`;
|
||||
this.layoutView(Orientation.VERTICAL);
|
||||
}
|
||||
}
|
||||
|
||||
class HorizontalViewItem extends ViewItem {
|
||||
|
||||
layout(): void {
|
||||
this.container.style.width = `${this.size}px`;
|
||||
this.layoutView(Orientation.HORIZONTAL);
|
||||
}
|
||||
}
|
||||
|
||||
interface ISashItem {
|
||||
|
@ -78,6 +147,8 @@ interface ISashDragState {
|
|||
minDelta: number;
|
||||
maxDelta: number;
|
||||
alt: boolean;
|
||||
snapIndex: number | undefined;
|
||||
snapLimitDelta: number | undefined;
|
||||
disposable: IDisposable;
|
||||
}
|
||||
|
||||
|
@ -104,7 +175,7 @@ export class SplitView extends Disposable {
|
|||
private size = 0;
|
||||
private contentSize = 0;
|
||||
private proportions: undefined | number[] = undefined;
|
||||
private viewItems: IViewItem[] = [];
|
||||
private viewItems: ViewItem[] = [];
|
||||
private sashItems: ISashItem[] = [];
|
||||
private sashDragState: ISashDragState;
|
||||
private state: State = State.Idle;
|
||||
|
@ -122,11 +193,11 @@ export class SplitView extends Disposable {
|
|||
}
|
||||
|
||||
get minimumSize(): number {
|
||||
return this.viewItems.reduce((r, item) => r + item.view.minimumSize, 0);
|
||||
return this.viewItems.reduce((r, item) => r + item.minimumSize, 0);
|
||||
}
|
||||
|
||||
get maximumSize(): number {
|
||||
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.view.maximumSize, 0);
|
||||
return this.length === 0 ? Number.POSITIVE_INFINITY : this.viewItems.reduce((r, item) => r + item.maximumSize, 0);
|
||||
}
|
||||
|
||||
private _orthogonalStartSash: Sash | undefined;
|
||||
|
@ -201,15 +272,6 @@ export class SplitView extends Disposable {
|
|||
const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container));
|
||||
const disposable = combinedDisposable(onChangeDisposable, containerDisposable);
|
||||
|
||||
const layoutContainer = this.orientation === Orientation.VERTICAL
|
||||
? () => item.container.style.height = `${item.size}px`
|
||||
: () => item.container.style.width = `${item.size}px`;
|
||||
|
||||
const layout = () => {
|
||||
layoutContainer();
|
||||
item.view.layout(item.size, this.orientation);
|
||||
};
|
||||
|
||||
let viewSize: number;
|
||||
|
||||
if (typeof size === 'number') {
|
||||
|
@ -220,7 +282,10 @@ export class SplitView extends Disposable {
|
|||
viewSize = view.minimumSize;
|
||||
}
|
||||
|
||||
const item: IViewItem = { view, container, size: viewSize, layout, disposable };
|
||||
const item = this.orientation === Orientation.VERTICAL
|
||||
? new VerticalViewItem(container, view, viewSize, disposable)
|
||||
: new HorizontalViewItem(container, view, viewSize, disposable);
|
||||
|
||||
this.viewItems.splice(index, 0, item);
|
||||
|
||||
// Add sash
|
||||
|
@ -280,7 +345,7 @@ export class SplitView extends Disposable {
|
|||
|
||||
// Remove view
|
||||
const viewItem = this.viewItems.splice(index, 1)[0];
|
||||
viewItem.disposable.dispose();
|
||||
const view = viewItem.dispose();
|
||||
|
||||
// Remove sash
|
||||
if (this.viewItems.length >= 1) {
|
||||
|
@ -296,7 +361,7 @@ export class SplitView extends Disposable {
|
|||
this.distributeViewSizes();
|
||||
}
|
||||
|
||||
return viewItem.view;
|
||||
return view;
|
||||
}
|
||||
|
||||
moveView(from: number, to: number): void {
|
||||
|
@ -327,6 +392,27 @@ export class SplitView extends Disposable {
|
|||
this.addView(fromView, toSize, to);
|
||||
}
|
||||
|
||||
isViewVisible(index: number): boolean {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
throw new Error('Index out of bounds');
|
||||
}
|
||||
|
||||
const viewItem = this.viewItems[index];
|
||||
return viewItem.visible;
|
||||
}
|
||||
|
||||
setViewVisible(index: number, visible: boolean): void {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
throw new Error('Index out of bounds');
|
||||
}
|
||||
|
||||
const viewItem = this.viewItems[index];
|
||||
viewItem.visible = visible;
|
||||
|
||||
this.distributeEmptySpace(index);
|
||||
this.layoutViews();
|
||||
}
|
||||
|
||||
private relayout(lowPriorityIndex?: number, highPriorityIndex?: number): void {
|
||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
const lowPriorityIndexes = typeof lowPriorityIndex === 'number' ? [lowPriorityIndex] : undefined;
|
||||
|
@ -344,14 +430,14 @@ export class SplitView extends Disposable {
|
|||
|
||||
if (!this.proportions) {
|
||||
const indexes = range(this.viewItems.length);
|
||||
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.Low);
|
||||
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].view.priority === LayoutPriority.High);
|
||||
const lowPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.Low);
|
||||
const highPriorityIndexes = indexes.filter(i => this.viewItems[i].priority === LayoutPriority.High);
|
||||
|
||||
this.resize(this.viewItems.length - 1, size - previousSize, undefined, lowPriorityIndexes, highPriorityIndexes);
|
||||
} else {
|
||||
for (let i = 0; i < this.viewItems.length; i++) {
|
||||
const item = this.viewItems[i];
|
||||
item.size = clamp(Math.round(this.proportions[i] * size), item.view.minimumSize, item.view.maximumSize);
|
||||
item.size = clamp(Math.round(this.proportions[i] * size), item.minimumSize, item.maximumSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -391,35 +477,72 @@ export class SplitView extends Disposable {
|
|||
|
||||
if (isLastSash) {
|
||||
const viewItem = this.viewItems[index];
|
||||
minDelta = (viewItem.view.minimumSize - viewItem.size) / 2;
|
||||
maxDelta = (viewItem.view.maximumSize - viewItem.size) / 2;
|
||||
minDelta = (viewItem.minimumSize - viewItem.size) / 2;
|
||||
maxDelta = (viewItem.maximumSize - viewItem.size) / 2;
|
||||
} else {
|
||||
const viewItem = this.viewItems[index + 1];
|
||||
minDelta = (viewItem.size - viewItem.view.maximumSize) / 2;
|
||||
maxDelta = (viewItem.size - viewItem.view.minimumSize) / 2;
|
||||
minDelta = (viewItem.size - viewItem.maximumSize) / 2;
|
||||
maxDelta = (viewItem.size - viewItem.minimumSize) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, disposable };
|
||||
let snapIndex: number | undefined;
|
||||
let snapLimitDelta: number | undefined;
|
||||
|
||||
if (!alt) {
|
||||
const upIndexes = range(index, -1);
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
|
||||
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);
|
||||
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);
|
||||
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);
|
||||
const minDelta = Math.max(minDeltaUp, minDeltaDown);
|
||||
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp);
|
||||
|
||||
const snapBefore = this.viewItems[index].snap;
|
||||
const snapAfter = this.viewItems[index + 1].snap;
|
||||
|
||||
if (snapBefore && snapAfter) {
|
||||
snapIndex = index + 1 < (this.viewItems.length - index - 1) ? index : index + 1;
|
||||
} else if (snapBefore) {
|
||||
snapIndex = index;
|
||||
} else if (snapAfter) {
|
||||
snapIndex = index + 1;
|
||||
}
|
||||
|
||||
if (typeof snapIndex === 'number') {
|
||||
if (this.viewItems[snapIndex].visible) {
|
||||
snapLimitDelta = snapIndex === index
|
||||
? minDelta - (this.viewItems[index].viewMinimumSize / 2)
|
||||
: maxDelta + (this.viewItems[index + 1].viewMinimumSize / 2);
|
||||
} else {
|
||||
snapLimitDelta = snapIndex === index
|
||||
? minDelta + (this.viewItems[index].viewMinimumSize / 2)
|
||||
: maxDelta - (this.viewItems[index + 1].viewMinimumSize / 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.sashDragState = { start, current: start, index, sizes, minDelta, maxDelta, alt, snapIndex, snapLimitDelta, disposable };
|
||||
};
|
||||
|
||||
resetSashDragState(start, alt);
|
||||
}
|
||||
|
||||
private onSashChange({ current }: ISashEvent): void {
|
||||
const { index, start, sizes, alt, minDelta, maxDelta } = this.sashDragState;
|
||||
const { index, start, sizes, alt, minDelta, maxDelta, snapIndex, snapLimitDelta } = this.sashDragState;
|
||||
this.sashDragState.current = current;
|
||||
|
||||
const delta = current - start;
|
||||
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta);
|
||||
const newDelta = this.resize(index, delta, sizes, undefined, undefined, minDelta, maxDelta, snapIndex, snapLimitDelta);
|
||||
|
||||
if (alt) {
|
||||
const isLastSash = index === this.sashItems.length - 1;
|
||||
const newSizes = this.viewItems.map(i => i.size);
|
||||
const viewItemIndex = isLastSash ? index : index + 1;
|
||||
const viewItem = this.viewItems[viewItemIndex];
|
||||
const newMinDelta = viewItem.size - viewItem.view.maximumSize;
|
||||
const newMaxDelta = viewItem.size - viewItem.view.minimumSize;
|
||||
const newMinDelta = viewItem.size - viewItem.maximumSize;
|
||||
const newMaxDelta = viewItem.size - viewItem.minimumSize;
|
||||
const resizeIndex = isLastSash ? index - 1 : index + 1;
|
||||
|
||||
this.resize(resizeIndex, -newDelta, newSizes, undefined, undefined, newMinDelta, newMaxDelta);
|
||||
|
@ -435,7 +558,7 @@ export class SplitView extends Disposable {
|
|||
this.saveProportions();
|
||||
}
|
||||
|
||||
private onViewChange(item: IViewItem, size: number | undefined): void {
|
||||
private onViewChange(item: ViewItem, size: number | undefined): void {
|
||||
const index = this.viewItems.indexOf(item);
|
||||
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
|
@ -443,7 +566,7 @@ export class SplitView extends Disposable {
|
|||
}
|
||||
|
||||
size = typeof size === 'number' ? size : item.size;
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
size = clamp(size, item.minimumSize, item.maximumSize);
|
||||
|
||||
if (this.inverseAltBehavior && index > 0) {
|
||||
// In this case, we want the view to grow or shrink both sides equally
|
||||
|
@ -470,13 +593,13 @@ export class SplitView extends Disposable {
|
|||
|
||||
const item = this.viewItems[index];
|
||||
size = Math.round(size);
|
||||
size = clamp(size, item.view.minimumSize, item.view.maximumSize);
|
||||
size = clamp(size, item.minimumSize, item.maximumSize);
|
||||
let delta = size - item.size;
|
||||
|
||||
if (delta !== 0 && index < this.viewItems.length - 1) {
|
||||
const downIndexes = range(index + 1, this.viewItems.length);
|
||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const collapseDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
||||
const expandDown = downIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaDown = clamp(delta, -expandDown, collapseDown);
|
||||
|
||||
this.resize(index, deltaDown);
|
||||
|
@ -485,8 +608,8 @@ export class SplitView extends Disposable {
|
|||
|
||||
if (delta !== 0 && index > 0) {
|
||||
const upIndexes = range(index - 1, -1);
|
||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].view.minimumSize), 0);
|
||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - this.viewItems[i].size), 0);
|
||||
const collapseUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].size - this.viewItems[i].minimumSize), 0);
|
||||
const expandUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - this.viewItems[i].size), 0);
|
||||
const deltaUp = clamp(-delta, -collapseUp, expandUp);
|
||||
|
||||
this.resize(index - 1, deltaUp);
|
||||
|
@ -521,7 +644,9 @@ export class SplitView extends Disposable {
|
|||
lowPriorityIndexes?: number[],
|
||||
highPriorityIndexes?: number[],
|
||||
overloadMinDelta: number = Number.NEGATIVE_INFINITY,
|
||||
overloadMaxDelta: number = Number.POSITIVE_INFINITY
|
||||
overloadMaxDelta: number = Number.POSITIVE_INFINITY,
|
||||
snapIndex?: number,
|
||||
snapLimitDelta?: number
|
||||
): number {
|
||||
if (index < 0 || index >= this.viewItems.length) {
|
||||
return 0;
|
||||
|
@ -550,18 +675,28 @@ export class SplitView extends Disposable {
|
|||
const downItems = downIndexes.map(i => this.viewItems[i]);
|
||||
const downSizes = downIndexes.map(i => sizes[i]);
|
||||
|
||||
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.minimumSize - sizes[i]), 0);
|
||||
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].view.maximumSize - sizes[i]), 0);
|
||||
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0);
|
||||
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.maximumSize), 0);
|
||||
const minDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].minimumSize - sizes[i]), 0);
|
||||
const maxDeltaUp = upIndexes.reduce((r, i) => r + (this.viewItems[i].maximumSize - sizes[i]), 0);
|
||||
const maxDeltaDown = downIndexes.length === 0 ? Number.POSITIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].minimumSize), 0);
|
||||
const minDeltaDown = downIndexes.length === 0 ? Number.NEGATIVE_INFINITY : downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].maximumSize), 0);
|
||||
const minDelta = Math.max(minDeltaUp, minDeltaDown, overloadMinDelta);
|
||||
const maxDelta = Math.min(maxDeltaDown, maxDeltaUp, overloadMaxDelta);
|
||||
|
||||
if (typeof snapIndex === 'number' && typeof snapLimitDelta === 'number') {
|
||||
const snapView = this.viewItems[snapIndex];
|
||||
|
||||
snapView.visible = snapIndex === index
|
||||
? delta >= snapLimitDelta // up
|
||||
: delta < snapLimitDelta; // down
|
||||
|
||||
return this.resize(index, delta, sizes, lowPriorityIndexes, highPriorityIndexes, overloadMinDelta, overloadMaxDelta);
|
||||
}
|
||||
|
||||
delta = clamp(delta, minDelta, maxDelta);
|
||||
|
||||
for (let i = 0, deltaUp = delta; i < upItems.length; i++) {
|
||||
const item = upItems[i];
|
||||
const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize);
|
||||
const size = clamp(upSizes[i] + deltaUp, item.minimumSize, item.maximumSize);
|
||||
const viewDelta = size - upSizes[i];
|
||||
|
||||
deltaUp -= viewDelta;
|
||||
|
@ -570,7 +705,7 @@ export class SplitView extends Disposable {
|
|||
|
||||
for (let i = 0, deltaDown = delta; i < downItems.length; i++) {
|
||||
const item = downItems[i];
|
||||
const size = clamp(downSizes[i] - deltaDown, item.view.minimumSize, item.view.maximumSize);
|
||||
const size = clamp(downSizes[i] - deltaDown, item.minimumSize, item.maximumSize);
|
||||
const viewDelta = size - downSizes[i];
|
||||
|
||||
deltaDown += viewDelta;
|
||||
|
@ -580,13 +715,19 @@ export class SplitView extends Disposable {
|
|||
return delta;
|
||||
}
|
||||
|
||||
private distributeEmptySpace(): void {
|
||||
let contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
private distributeEmptySpace(lowPriorityIndex?: number): void {
|
||||
const contentSize = this.viewItems.reduce((r, i) => r + i.size, 0);
|
||||
let emptyDelta = this.size - contentSize;
|
||||
|
||||
for (let i = this.viewItems.length - 1; emptyDelta !== 0 && i >= 0; i--) {
|
||||
const item = this.viewItems[i];
|
||||
const size = clamp(item.size + emptyDelta, item.view.minimumSize, item.view.maximumSize);
|
||||
const indexes = range(this.viewItems.length - 1, -1);
|
||||
|
||||
if (typeof lowPriorityIndex === 'number') {
|
||||
pushToEnd(indexes, lowPriorityIndex);
|
||||
}
|
||||
|
||||
for (let i = 0; emptyDelta !== 0 && i < indexes.length; i++) {
|
||||
const item = this.viewItems[indexes[i]];
|
||||
const size = clamp(item.size + emptyDelta, item.minimumSize, item.maximumSize);
|
||||
const viewDelta = size - item.size;
|
||||
|
||||
emptyDelta -= viewDelta;
|
||||
|
@ -606,30 +747,43 @@ export class SplitView extends Disposable {
|
|||
|
||||
// Update sashes enablement
|
||||
let previous = false;
|
||||
const collapsesDown = this.viewItems.map(i => previous = (i.size - i.view.minimumSize > 0) || previous);
|
||||
const collapsesDown = this.viewItems.map(i => previous = (i.size - i.minimumSize > 0) || previous);
|
||||
|
||||
previous = false;
|
||||
const expandsDown = this.viewItems.map(i => previous = (i.view.maximumSize - i.size > 0) || previous);
|
||||
const expandsDown = this.viewItems.map(i => previous = (i.maximumSize - i.size > 0) || previous);
|
||||
|
||||
const reverseViews = [...this.viewItems].reverse();
|
||||
previous = false;
|
||||
const collapsesUp = reverseViews.map(i => previous = (i.size - i.view.minimumSize > 0) || previous).reverse();
|
||||
const collapsesUp = reverseViews.map(i => previous = (i.size - i.minimumSize > 0) || previous).reverse();
|
||||
|
||||
previous = false;
|
||||
const expandsUp = reverseViews.map(i => previous = (i.view.maximumSize - i.size > 0) || previous).reverse();
|
||||
const expandsUp = reverseViews.map(i => previous = (i.maximumSize - i.size > 0) || previous).reverse();
|
||||
|
||||
this.sashItems.forEach((s, i) => {
|
||||
const min = !(collapsesDown[i] && expandsUp[i + 1]);
|
||||
const max = !(expandsDown[i] && collapsesUp[i + 1]);
|
||||
|
||||
if (min && max) {
|
||||
if (!this.viewItems[i].visible) {
|
||||
s.sash.state = SashState.Disabled;
|
||||
} else if (min && !max) {
|
||||
s.sash.state = SashState.Minimum;
|
||||
} else if (!min && max) {
|
||||
s.sash.state = SashState.Maximum;
|
||||
} else {
|
||||
s.sash.state = SashState.Enabled;
|
||||
const min = !(collapsesDown[i] && expandsUp[i + 1]);
|
||||
const max = !(expandsDown[i] && collapsesUp[i + 1]);
|
||||
|
||||
if (min && max) {
|
||||
const before = !range(0, i + 1).some(i => !this.viewItems[i].snap || this.viewItems[i].visible);
|
||||
const after = !range(i + 1, this.viewItems.length).some(i => !this.viewItems[i].snap || this.viewItems[i].visible);
|
||||
|
||||
if (before) {
|
||||
s.sash.state = SashState.Minimum;
|
||||
} else if (after) {
|
||||
s.sash.state = SashState.Maximum;
|
||||
} else {
|
||||
s.sash.state = SashState.Disabled;
|
||||
}
|
||||
} else if (min && !max) {
|
||||
s.sash.state = SashState.Minimum;
|
||||
} else if (!min && max) {
|
||||
s.sash.state = SashState.Maximum;
|
||||
} else {
|
||||
s.sash.state = SashState.Enabled;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -651,7 +805,7 @@ export class SplitView extends Disposable {
|
|||
dispose(): void {
|
||||
super.dispose();
|
||||
|
||||
this.viewItems.forEach(i => i.disposable.dispose());
|
||||
this.viewItems.forEach(i => i.dispose());
|
||||
this.viewItems = [];
|
||||
|
||||
this.sashItems.forEach(i => i.disposable.dispose());
|
||||
|
|
|
@ -17,5 +17,5 @@
|
|||
}
|
||||
|
||||
.hc-black .monaco-toolbar .action-label.toolbar-toggle-more {
|
||||
background-image: url('ellipsis-dark.svg');
|
||||
background-image: url('ellipsis-hc.svg');
|
||||
}
|
|
@ -7,6 +7,7 @@ import * as errors from 'vs/base/common/errors';
|
|||
import * as uuid from 'vs/base/common/uuid';
|
||||
import { networkInterfaces } from 'os';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import { getMac } from 'vs/base/node/macAddress';
|
||||
|
||||
// http://www.techrepublic.com/blog/data-center/mac-address-scorecard-for-common-virtual-machine-platforms/
|
||||
// VMware ESX 3, Server, Workstation, Player 00-50-56, 00-0C-29, 00-05-69
|
||||
|
@ -76,35 +77,25 @@ export const virtualMachineHint: { value(): number } = new class {
|
|||
};
|
||||
|
||||
let machineId: Promise<string>;
|
||||
export function getMachineId(): Promise<string> {
|
||||
return machineId || (machineId = getMacMachineId()
|
||||
.then(id => id || uuid.generateUuid())); // fallback, generate a UUID
|
||||
export async function getMachineId(): Promise<string> {
|
||||
if (!machineId) {
|
||||
machineId = (async () => {
|
||||
const id = await getMacMachineId();
|
||||
|
||||
return id || uuid.generateUuid(); // fallback, generate a UUID
|
||||
})();
|
||||
}
|
||||
|
||||
return machineId;
|
||||
}
|
||||
|
||||
function getMacMachineId(): Promise<string> {
|
||||
return new Promise<string>(resolve => {
|
||||
Promise.all([import('crypto'), import('getmac')]).then(([crypto, getmac]) => {
|
||||
try {
|
||||
getmac.getMac((error, macAddress) => {
|
||||
if (!error) {
|
||||
resolve(crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex'));
|
||||
} else {
|
||||
resolve(undefined);
|
||||
}
|
||||
});
|
||||
|
||||
// Timeout due to hang with reduced privileges #58392
|
||||
// TODO@sbatten: Remove this when getmac is patched
|
||||
setTimeout(() => {
|
||||
resolve(undefined);
|
||||
}, 10000);
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
resolve(undefined);
|
||||
}
|
||||
}, err => {
|
||||
errors.onUnexpectedError(err);
|
||||
resolve(undefined);
|
||||
});
|
||||
});
|
||||
async function getMacMachineId(): Promise<string | undefined> {
|
||||
try {
|
||||
const crypto = await import('crypto');
|
||||
const macAddress = await getMac();
|
||||
return crypto.createHash('sha256').update(macAddress, 'utf8').digest('hex');
|
||||
} catch (err) {
|
||||
errors.onUnexpectedError(err);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
|
69
src/vs/base/node/macAddress.ts
Normal 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);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -3,8 +3,8 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import * as getmac from 'getmac';
|
||||
import { getMachineId } from 'vs/base/node/id';
|
||||
import { getMac } from 'vs/base/node/macAddress';
|
||||
|
||||
suite('ID', () => {
|
||||
|
||||
|
@ -16,9 +16,7 @@ suite('ID', () => {
|
|||
});
|
||||
|
||||
test('getMac', () => {
|
||||
return new Promise<string>((resolve, reject) => {
|
||||
getmac.getMac((err, macAddress) => err ? reject(err) : resolve(macAddress));
|
||||
}).then(macAddress => {
|
||||
return getMac().then(macAddress => {
|
||||
assert.ok(/^([0-9A-Fa-f]{2}[:-]){5}([0-9A-Fa-f]{2})$/.test(macAddress), `Expected a MAC address, got: ${macAddress}`);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -16,7 +16,7 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ
|
|||
import { ExtensionManagementChannel } from 'vs/platform/extensionManagement/node/extensionManagementIpc';
|
||||
import { IExtensionManagementService, IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { ConfigurationService } from 'vs/platform/configuration/node/configurationService';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
|
@ -55,6 +55,8 @@ import { FileService } from 'vs/platform/files/common/fileService';
|
|||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/electron-browser/diskFileSystemProvider';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { ProductService } from 'vs/platform/product/node/productService';
|
||||
|
||||
export interface ISharedProcessConfiguration {
|
||||
readonly machineId: string;
|
||||
|
@ -114,6 +116,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat
|
|||
services.set(IConfigurationService, configurationService);
|
||||
services.set(IRequestService, new SyncDescriptor(RequestService));
|
||||
services.set(IDownloadService, new SyncDescriptor(DownloadService));
|
||||
services.set(IProductService, new SyncDescriptor(ProductService));
|
||||
|
||||
const mainProcessService = new MainProcessService(server, mainRouter);
|
||||
services.set(IMainProcessService, mainProcessService);
|
||||
|
|
|
@ -90,6 +90,7 @@ import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemPro
|
|||
export class CodeApplication extends Disposable {
|
||||
|
||||
private static readonly MACHINE_ID_KEY = 'telemetry.machineId';
|
||||
private static readonly TRUE_MACHINE_ID_KEY = 'telemetry.trueMachineId';
|
||||
|
||||
private windowsMainService: IWindowsMainService | undefined;
|
||||
|
||||
|
@ -363,8 +364,8 @@ export class CodeApplication extends Disposable {
|
|||
|
||||
// Resolve unique machine ID
|
||||
this.logService.trace('Resolving machine identifier...');
|
||||
const machineId = await this.resolveMachineId();
|
||||
this.logService.trace(`Resolved machine identifier: ${machineId}`);
|
||||
const { machineId, trueMachineId } = await this.resolveMachineId();
|
||||
this.logService.trace(`Resolved machine identifier: ${machineId} (trueMachineId: ${trueMachineId})`);
|
||||
|
||||
// Spawn shared process after the first window has opened and 3s have passed
|
||||
const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv);
|
||||
|
@ -378,7 +379,7 @@ export class CodeApplication extends Disposable {
|
|||
});
|
||||
|
||||
// Services
|
||||
const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient);
|
||||
const appInstantiationService = await this.createServices(machineId, trueMachineId, sharedProcess, sharedProcessClient);
|
||||
|
||||
// Create driver
|
||||
if (this.environmentService.driverHandle) {
|
||||
|
@ -404,7 +405,7 @@ export class CodeApplication extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
private async resolveMachineId(): Promise<string> {
|
||||
private async resolveMachineId(): Promise<{ machineId: string, trueMachineId?: string }> {
|
||||
|
||||
// We cache the machineId for faster lookups on startup
|
||||
// and resolve it only once initially if not cached
|
||||
|
@ -415,10 +416,21 @@ export class CodeApplication extends Disposable {
|
|||
this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId);
|
||||
}
|
||||
|
||||
return machineId;
|
||||
// Check if machineId is hashed iBridge Device
|
||||
let trueMachineId: string | undefined;
|
||||
if (isMacintosh && machineId === '6c9d2bc8f91b89624add29c0abeae7fb42bf539fa1cdb2e3e57cd668fa9bcead') {
|
||||
trueMachineId = this.stateService.getItem<string>(CodeApplication.TRUE_MACHINE_ID_KEY);
|
||||
if (!trueMachineId) {
|
||||
trueMachineId = await getMachineId();
|
||||
|
||||
this.stateService.setItem(CodeApplication.TRUE_MACHINE_ID_KEY, trueMachineId);
|
||||
}
|
||||
}
|
||||
|
||||
return { machineId, trueMachineId };
|
||||
}
|
||||
|
||||
private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
|
||||
private async createServices(machineId: string, trueMachineId: string | undefined, sharedProcess: SharedProcess, sharedProcessClient: Promise<Client<string>>): Promise<IInstantiationService> {
|
||||
const services = new ServiceCollection();
|
||||
|
||||
// Files
|
||||
|
@ -473,7 +485,7 @@ export class CodeApplication extends Disposable {
|
|||
const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService));
|
||||
const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath);
|
||||
const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath];
|
||||
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths };
|
||||
const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths, trueMachineId };
|
||||
|
||||
services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config]));
|
||||
} else {
|
||||
|
|
|
@ -21,10 +21,12 @@ import { IWorkspaceIdentifier, IWorkspacesMainService } from 'vs/platform/worksp
|
|||
import { IBackupMainService } from 'vs/platform/backup/common/backup';
|
||||
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
||||
import * as perf from 'vs/base/common/performance';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { RunOnceScheduler } from 'vs/base/common/async';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
|
||||
const RUN_TEXTMATE_IN_WORKER = false;
|
||||
|
||||
|
@ -76,6 +78,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
config: IWindowCreationOptions,
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IThemeMainService private readonly themeMainService: IThemeMainService,
|
||||
@IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService,
|
||||
|
@ -307,7 +310,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {
|
|||
private handleMarketplaceRequests(): void {
|
||||
|
||||
// Resolve marketplace headers
|
||||
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(this.environmentService);
|
||||
this.marketplaceHeadersPromise = resolveMarketplaceHeaders(pkg.version, this.environmentService, this.fileService);
|
||||
|
||||
// Inject headers when requests are incoming
|
||||
const urls = ['https://marketplace.visualstudio.com/*', 'https://*.vsassets.io/*'];
|
||||
|
|
|
@ -207,46 +207,17 @@ export class WindowsManager extends Disposable implements IWindowsMainService {
|
|||
this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this);
|
||||
|
||||
this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
|
||||
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers());
|
||||
this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.installWindowsMutex());
|
||||
}
|
||||
|
||||
private setupNativeHelpers(): void {
|
||||
private installWindowsMutex(): void {
|
||||
if (isWindows) {
|
||||
|
||||
// Setup Windows mutex
|
||||
try {
|
||||
const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex;
|
||||
const mutex = new WindowsMutex(product.win32MutexName);
|
||||
once(this.lifecycleService.onWillShutdown)(() => mutex.release());
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
|
||||
if (!this.environmentService.isBuilt) {
|
||||
this.showMessageBox({
|
||||
title: product.nameLong,
|
||||
type: 'warning',
|
||||
message: 'Failed to load windows-mutex!',
|
||||
detail: e.toString(),
|
||||
noLink: true
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Dev only: Ensure Windows foreground love module is present
|
||||
if (!this.environmentService.isBuilt) {
|
||||
try {
|
||||
require.__$__nodeRequire('windows-foreground-love');
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
|
||||
this.showMessageBox({
|
||||
title: product.nameLong,
|
||||
type: 'warning',
|
||||
message: 'Failed to load windows-foreground-love!',
|
||||
detail: e.toString(),
|
||||
noLink: true
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/
|
|||
import { EnvironmentService } from 'vs/platform/environment/node/environmentService';
|
||||
import { IExtensionManagementService, IExtensionGalleryService, IGalleryExtension, ILocalExtension } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionManagementService } from 'vs/platform/extensionManagement/node/extensionManagementService';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { ExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { combinedAppender, NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { TelemetryService, ITelemetryServiceConfig } from 'vs/platform/telemetry/common/telemetryService';
|
||||
|
@ -46,6 +46,8 @@ import { FileService } from 'vs/platform/files/common/fileService';
|
|||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
import { ProductService } from 'vs/platform/product/node/productService';
|
||||
|
||||
const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id);
|
||||
const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id);
|
||||
|
@ -301,6 +303,7 @@ export async function main(argv: ParsedArgs): Promise<void> {
|
|||
services.set(ILogService, logService);
|
||||
services.set(IConfigurationService, configurationService);
|
||||
services.set(IStateService, new SyncDescriptor(StateService));
|
||||
services.set(IProductService, new SyncDescriptor(ProductService));
|
||||
|
||||
// Files
|
||||
const fileService = new FileService(logService);
|
||||
|
|
28
src/vs/code/test/electron-main/nativeHelpers.test.ts
Normal 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.');
|
||||
});
|
||||
});
|
|
@ -80,7 +80,7 @@ export class QuickFixController extends Disposable implements IEditorContributio
|
|||
this._ui.update(newState);
|
||||
}
|
||||
|
||||
public showCodeActions(actions: Promise<CodeActionSet>, at: IAnchor | IPosition) {
|
||||
public showCodeActions(actions: CodeActionSet, at: IAnchor | IPosition) {
|
||||
return this._ui.showCodeActionList(actions, at);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,15 +95,7 @@ export class CodeActionUi extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
public async showCodeActionList(codeActions: Promise<CodeActionSet>, at?: IAnchor | IPosition): Promise<void> {
|
||||
let actions: CodeActionSet;
|
||||
try {
|
||||
actions = await codeActions;
|
||||
} catch (e) {
|
||||
onUnexpectedError(e);
|
||||
return;
|
||||
}
|
||||
|
||||
public async showCodeActionList(actions: CodeActionSet, at?: IAnchor | IPosition): Promise<void> {
|
||||
this._codeActionWidget.show(actions, at);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser';
|
|||
import { Position } from 'vs/editor/common/core/position';
|
||||
import { IRange, Range } from 'vs/editor/common/core/range';
|
||||
import { ModelDecorationOptions } from 'vs/editor/common/model/textModel';
|
||||
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor, CodeAction } from 'vs/editor/common/modes';
|
||||
import { DocumentColorProvider, Hover as MarkdownHover, HoverProviderRegistry, IColor } from 'vs/editor/common/modes';
|
||||
import { getColorPresentations } from 'vs/editor/contrib/colorPicker/color';
|
||||
import { ColorDetector } from 'vs/editor/contrib/colorPicker/colorDetector';
|
||||
import { ColorPickerModel } from 'vs/editor/contrib/colorPicker/colorPickerModel';
|
||||
|
@ -517,21 +517,6 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
|||
const hoverElement = $('div.hover-row.status-bar');
|
||||
const disposables = new DisposableStore();
|
||||
const actionsElement = dom.append(hoverElement, $('div.actions'));
|
||||
disposables.add(this.renderAction(actionsElement, {
|
||||
label: nls.localize('quick fixes', "Quick Fix..."),
|
||||
commandId: QuickFixAction.Id,
|
||||
run: async (target) => {
|
||||
const codeActionsPromise = this.getCodeActions(markerHover.marker);
|
||||
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
|
||||
|
||||
const controller = QuickFixController.get(this._editor);
|
||||
const elementPosition = dom.getDomNodePagePosition(target);
|
||||
controller.showCodeActions(codeActionsPromise, {
|
||||
x: elementPosition.left + 6,
|
||||
y: elementPosition.top + elementPosition.height + 6
|
||||
});
|
||||
}
|
||||
}));
|
||||
if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) {
|
||||
disposables.add(this.renderAction(actionsElement, {
|
||||
label: nls.localize('peek problem', "Peek Problem"),
|
||||
|
@ -543,27 +528,61 @@ export class ModesContentHoverWidget extends ContentHoverWidget {
|
|||
}
|
||||
}));
|
||||
}
|
||||
|
||||
const quickfixPlaceholderElement = dom.append(actionsElement, $('div'));
|
||||
quickfixPlaceholderElement.style.opacity = '0';
|
||||
quickfixPlaceholderElement.style.transition = 'opacity 0.2s';
|
||||
setTimeout(() => quickfixPlaceholderElement.style.opacity = '1', 200);
|
||||
quickfixPlaceholderElement.textContent = nls.localize('checkingForQuickFixes', "Checking for quick fixes...");
|
||||
disposables.add(toDisposable(() => quickfixPlaceholderElement.remove()));
|
||||
|
||||
|
||||
const codeActionsPromise = this.getCodeActions(markerHover.marker);
|
||||
disposables.add(toDisposable(() => codeActionsPromise.cancel()));
|
||||
codeActionsPromise.then(actions => {
|
||||
quickfixPlaceholderElement.style.transition = '';
|
||||
quickfixPlaceholderElement.style.opacity = '1';
|
||||
|
||||
if (!actions.actions.length) {
|
||||
actions.dispose();
|
||||
quickfixPlaceholderElement.textContent = nls.localize('noQuickFixes', "No quick fixes available");
|
||||
return;
|
||||
}
|
||||
quickfixPlaceholderElement.remove();
|
||||
|
||||
let showing = false;
|
||||
disposables.add(toDisposable(() => {
|
||||
if (!showing) {
|
||||
actions.dispose();
|
||||
}
|
||||
}));
|
||||
|
||||
disposables.add(this.renderAction(actionsElement, {
|
||||
label: nls.localize('quick fixes', "Quick Fix..."),
|
||||
commandId: QuickFixAction.Id,
|
||||
run: (target) => {
|
||||
showing = true;
|
||||
const controller = QuickFixController.get(this._editor);
|
||||
const elementPosition = dom.getDomNodePagePosition(target);
|
||||
controller.showCodeActions(actions, {
|
||||
x: elementPosition.left + 6,
|
||||
y: elementPosition.top + elementPosition.height + 6
|
||||
});
|
||||
}
|
||||
}));
|
||||
});
|
||||
|
||||
this.renderDisposable.value = disposables;
|
||||
return hoverElement;
|
||||
}
|
||||
|
||||
private getCodeActions(marker: IMarker): CancelablePromise<CodeActionSet> {
|
||||
const noAction: CodeAction = {
|
||||
title: nls.localize('editor.action.quickFix.noneMessage', "No code actions available"),
|
||||
kind: CodeActionKind.QuickFix.value,
|
||||
};
|
||||
return createCancelablePromise(async (cancellationToken): Promise<CodeActionSet> => {
|
||||
const result = await getCodeActions(
|
||||
return createCancelablePromise(cancellationToken => {
|
||||
return getCodeActions(
|
||||
this._editor.getModel()!,
|
||||
new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn),
|
||||
{ type: 'manual', filter: { kind: CodeActionKind.QuickFix } },
|
||||
cancellationToken);
|
||||
|
||||
return {
|
||||
actions: result.actions.length ? result.actions : [noAction],
|
||||
hasAutoFix: result.hasAutoFix,
|
||||
dispose: () => result.dispose(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -3,8 +3,6 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { tmpdir } from 'os';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import { getErrorMessage, isPromiseCanceledError, canceled } from 'vs/base/common/errors';
|
||||
import { StatisticType, IGalleryExtension, IExtensionGalleryService, IGalleryExtensionAsset, IQueryOptions, SortBy, SortOrder, IExtensionIdentifier, IReportedExtension, InstallOperation, ITranslation, IGalleryExtensionVersion, IGalleryExtensionAssets, isIExtensionIdentifier } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { getGalleryExtensionId, getGalleryExtensionTelemetryData, adoptToGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
|
@ -12,11 +10,8 @@ import { assign, getOrDefault } from 'vs/base/common/objects';
|
|||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IPager } from 'vs/base/common/paging';
|
||||
import { IRequestService, IRequestOptions, IRequestContext, asJson, asText } from 'vs/platform/request/common/request';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
import product from 'vs/platform/product/node/product';
|
||||
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
|
||||
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { writeFileSync, readFile } from 'vs/base/node/pfs';
|
||||
import { generateUuid, isUUID } from 'vs/base/common/uuid';
|
||||
import { values } from 'vs/base/common/map';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
|
@ -24,6 +19,9 @@ import { ILogService } from 'vs/platform/log/common/log';
|
|||
import { IExtensionManifest } from 'vs/platform/extensions/common/extensions';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
|
||||
interface IRawGalleryExtensionFile {
|
||||
assetType: string;
|
||||
|
@ -339,11 +337,12 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
@IEnvironmentService private readonly environmentService: IEnvironmentService,
|
||||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@IFileService private readonly fileService: IFileService,
|
||||
@IProductService private readonly productService: IProductService,
|
||||
) {
|
||||
const config = product.extensionsGallery;
|
||||
const config = productService.extensionsGallery;
|
||||
this.extensionsGalleryUrl = config && config.serviceUrl;
|
||||
this.extensionsControlUrl = config && config.controlUrl;
|
||||
this.commonHeadersPromise = resolveMarketplaceHeaders(this.environmentService);
|
||||
this.commonHeadersPromise = resolveMarketplaceHeaders(productService.version, this.environmentService, this.fileService);
|
||||
}
|
||||
|
||||
private api(path = ''): string {
|
||||
|
@ -356,7 +355,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
|
||||
getCompatibleExtension(arg1: IExtensionIdentifier | IGalleryExtension, version?: string): Promise<IGalleryExtension | null> {
|
||||
const extension: IGalleryExtension | null = isIExtensionIdentifier(arg1) ? null : arg1;
|
||||
if (extension && extension.properties.engine && isEngineValid(extension.properties.engine)) {
|
||||
if (extension && extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
|
||||
return Promise.resolve(extension);
|
||||
}
|
||||
const { id, uuid } = extension ? extension.identifier : <IExtensionIdentifier>arg1;
|
||||
|
@ -382,7 +381,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
const versionAsset = rawExtension.versions.filter(v => v.version === version)[0];
|
||||
if (versionAsset) {
|
||||
const extension = toExtension(rawExtension, versionAsset, 0, query);
|
||||
if (extension.properties.engine && isEngineValid(extension.properties.engine)) {
|
||||
if (extension.properties.engine && isEngineValid(extension.properties.engine, this.productService.version)) {
|
||||
return extension;
|
||||
}
|
||||
}
|
||||
|
@ -535,9 +534,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
});
|
||||
}
|
||||
|
||||
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string> {
|
||||
download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<URI> {
|
||||
this.logService.trace('ExtensionGalleryService#download', extension.identifier.id);
|
||||
const zipPath = path.join(tmpdir(), generateUuid());
|
||||
const zip = joinPath(location, generateUuid());
|
||||
const data = getGalleryExtensionTelemetryData(extension);
|
||||
const startTime = new Date().getTime();
|
||||
/* __GDPR__
|
||||
|
@ -557,9 +556,9 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
} : extension.assets.download;
|
||||
|
||||
return this.getAsset(downloadAsset)
|
||||
.then(context => this.fileService.writeFile(URI.file(zipPath), context.stream))
|
||||
.then(context => this.fileService.writeFile(zip, context.stream))
|
||||
.then(() => log(new Date().getTime() - startTime))
|
||||
.then(() => zipPath);
|
||||
.then(() => zip);
|
||||
}
|
||||
|
||||
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
|
||||
|
@ -615,7 +614,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
return this.queryGallery(query, CancellationToken.None).then(({ galleryExtensions }) => {
|
||||
if (galleryExtensions.length) {
|
||||
if (compatible) {
|
||||
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine) ? v : null)))
|
||||
return Promise.all(galleryExtensions[0].versions.map(v => this.getEngine(v).then(engine => isEngineValid(engine, this.productService.version) ? v : null)))
|
||||
.then(versions => versions
|
||||
.filter(v => !!v)
|
||||
.map(v => ({ version: v!.version, date: v!.lastUpdated })));
|
||||
|
@ -701,7 +700,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
if (!engine) {
|
||||
return null;
|
||||
}
|
||||
if (isEngineValid(engine)) {
|
||||
if (isEngineValid(engine, this.productService.version)) {
|
||||
return Promise.resolve(version);
|
||||
}
|
||||
}
|
||||
|
@ -733,7 +732,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
const version = versions[0];
|
||||
return this.getEngine(version)
|
||||
.then(engine => {
|
||||
if (!isEngineValid(engine)) {
|
||||
if (!isEngineValid(engine, this.productService.version)) {
|
||||
return this.getLastValidExtensionVersionRecursively(extension, versions.slice(1));
|
||||
}
|
||||
|
||||
|
@ -774,24 +773,30 @@ export class ExtensionGalleryService implements IExtensionGalleryService {
|
|||
}
|
||||
}
|
||||
|
||||
export function resolveMarketplaceHeaders(environmentService: IEnvironmentService): Promise<{ [key: string]: string; }> {
|
||||
const marketplaceMachineIdFile = path.join(environmentService.userDataPath, 'machineid');
|
||||
export async function resolveMarketplaceHeaders(version: string, environmentService: IEnvironmentService, fileService: IFileService): Promise<{ [key: string]: string; }> {
|
||||
const marketplaceMachineIdFile = joinPath(URI.file(environmentService.userDataPath), 'machineid');
|
||||
|
||||
return readFile(marketplaceMachineIdFile, 'utf8')
|
||||
.then<string | null>(contents => isUUID(contents) ? contents : null, () => null /* error reading ID file */)
|
||||
.then(uuid => {
|
||||
if (!uuid) {
|
||||
uuid = generateUuid();
|
||||
try {
|
||||
writeFileSync(marketplaceMachineIdFile, uuid);
|
||||
} catch (error) {
|
||||
//noop
|
||||
}
|
||||
}
|
||||
return {
|
||||
'X-Market-Client-Id': `VSCode ${pkg.version}`,
|
||||
'User-Agent': `VSCode ${pkg.version}`,
|
||||
'X-Market-User-Id': uuid
|
||||
};
|
||||
});
|
||||
let uuid: string | null = null;
|
||||
|
||||
try {
|
||||
const contents = await fileService.readFile(marketplaceMachineIdFile);
|
||||
const value = contents.value.toString();
|
||||
uuid = isUUID(value) ? value : null;
|
||||
} catch (e) {
|
||||
uuid = null;
|
||||
}
|
||||
|
||||
if (!uuid) {
|
||||
uuid = generateUuid();
|
||||
try {
|
||||
await fileService.writeFile(marketplaceMachineIdFile, VSBuffer.fromString(uuid));
|
||||
} catch (error) {
|
||||
//noop
|
||||
}
|
||||
}
|
||||
return {
|
||||
'X-Market-Client-Id': `VSCode ${version}`,
|
||||
'User-Agent': `VSCode ${version}`,
|
||||
'X-Market-User-Id': uuid
|
||||
};
|
||||
}
|
|
@ -151,7 +151,7 @@ export interface IExtensionGalleryService {
|
|||
isEnabled(): boolean;
|
||||
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string>;
|
||||
download(extension: IGalleryExtension, location: URI, operation: InstallOperation): Promise<URI>;
|
||||
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void>;
|
||||
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string>;
|
||||
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest | null>;
|
||||
|
|
|
@ -35,7 +35,7 @@ import { ExtensionsManifestCache } from 'vs/platform/extensionManagement/node/ex
|
|||
import { ExtensionsLifecycle } from 'vs/platform/extensionManagement/node/extensionLifecycle';
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator';
|
||||
import { isEngineValid } from 'vs/platform/extensions/common/extensionValidator';
|
||||
import { tmpdir } from 'os';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
|
@ -197,7 +197,7 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
|||
.then(manifest => {
|
||||
const identifier = { id: getGalleryExtensionId(manifest.publisher, manifest.name) };
|
||||
let operation: InstallOperation = InstallOperation.Install;
|
||||
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode)) {
|
||||
if (manifest.engines && manifest.engines.vscode && !isEngineValid(manifest.engines.vscode, pkg.version)) {
|
||||
return Promise.reject(new Error(nls.localize('incompatible', "Unable to install extension '{0}' as it is not compatible with VS Code '{1}'.", identifier.id, pkg.version)));
|
||||
}
|
||||
const identifierWithVersion = new ExtensionIdentifierWithVersion(identifier, manifest.version);
|
||||
|
@ -391,9 +391,10 @@ export class ExtensionManagementService extends Disposable implements IExtension
|
|||
};
|
||||
|
||||
this.logService.trace('Started downloading extension:', extension.identifier.id);
|
||||
return this.galleryService.download(extension, operation)
|
||||
return this.galleryService.download(extension, URI.file(tmpdir()), operation)
|
||||
.then(
|
||||
zipPath => {
|
||||
zip => {
|
||||
const zipPath = zip.fsPath;
|
||||
this.logService.info('Downloaded extension:', extension.identifier.id, zipPath);
|
||||
return getManifest(zipPath)
|
||||
.then(
|
||||
|
|
|
@ -10,15 +10,32 @@ import { parseArgs } from 'vs/platform/environment/node/argv';
|
|||
import { getRandomTestPath } from 'vs/base/test/node/testUtils';
|
||||
import { join } from 'vs/base/common/path';
|
||||
import { mkdirp, RimRafMode, rimraf } from 'vs/base/node/pfs';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService';
|
||||
import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/common/extensionGalleryService';
|
||||
import { isUUID } from 'vs/base/common/uuid';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { NullLogService } from 'vs/platform/log/common/log';
|
||||
import { DiskFileSystemProvider } from 'vs/platform/files/node/diskFileSystemProvider';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
|
||||
suite('Extension Gallery Service', () => {
|
||||
const parentDir = getRandomTestPath(os.tmpdir(), 'vsctests', 'extensiongalleryservice');
|
||||
const marketplaceHome = join(parentDir, 'Marketplace');
|
||||
let fileService: IFileService;
|
||||
let disposables: DisposableStore;
|
||||
|
||||
setup(done => {
|
||||
|
||||
disposables = new DisposableStore();
|
||||
fileService = new FileService(new NullLogService());
|
||||
disposables.add(fileService);
|
||||
|
||||
const diskFileSystemProvider = new DiskFileSystemProvider(new NullLogService());
|
||||
disposables.add(diskFileSystemProvider);
|
||||
fileService.registerProvider(Schemas.file, diskFileSystemProvider);
|
||||
|
||||
// Delete any existing backups completely and then re-create it.
|
||||
rimraf(marketplaceHome, RimRafMode.MOVE).then(() => {
|
||||
mkdirp(marketplaceHome).then(() => {
|
||||
|
@ -28,6 +45,7 @@ suite('Extension Gallery Service', () => {
|
|||
});
|
||||
|
||||
teardown(done => {
|
||||
disposables.clear();
|
||||
rimraf(marketplaceHome, RimRafMode.MOVE).then(done, done);
|
||||
});
|
||||
|
||||
|
@ -35,10 +53,10 @@ suite('Extension Gallery Service', () => {
|
|||
const args = ['--user-data-dir', marketplaceHome];
|
||||
const environmentService = new EnvironmentService(parseArgs(args), process.execPath);
|
||||
|
||||
return resolveMarketplaceHeaders(environmentService).then(headers => {
|
||||
return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers => {
|
||||
assert.ok(isUUID(headers['X-Market-User-Id']));
|
||||
|
||||
return resolveMarketplaceHeaders(environmentService).then(headers2 => {
|
||||
return resolveMarketplaceHeaders(pkg.version, environmentService, fileService).then(headers2 => {
|
||||
assert.equal(headers['X-Market-User-Id'], headers2['X-Market-User-Id']);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as nls from 'vs/nls';
|
||||
import pkg from 'vs/platform/product/node/package';
|
||||
|
||||
export interface IParsedVersion {
|
||||
hasCaret: boolean;
|
||||
|
@ -222,9 +221,9 @@ export function isValidExtensionVersion(version: string, extensionDesc: IReduced
|
|||
return isVersionValid(version, extensionDesc.engines.vscode, notices);
|
||||
}
|
||||
|
||||
export function isEngineValid(engine: string): boolean {
|
||||
export function isEngineValid(engine: string, version: string): boolean {
|
||||
// TODO@joao: discuss with alex '*' doesn't seem to be a valid engine version
|
||||
return engine === '*' || isVersionValid(pkg.version, engine);
|
||||
return engine === '*' || isVersionValid(version, engine);
|
||||
}
|
||||
|
||||
export function isVersionValid(currentVersion: string, requestedVersion: string, notices: string[] = []): boolean {
|
|
@ -3,7 +3,7 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/node/extensionValidator';
|
||||
import { INormalizedVersion, IParsedVersion, IReducedExtensionDescription, isValidExtensionVersion, isValidVersion, isValidVersionStr, normalizeVersion, parseVersion } from 'vs/platform/extensions/common/extensionValidator';
|
||||
|
||||
suite('Extension Version Validator', () => {
|
||||
|
||||
|
|
|
@ -1696,7 +1696,9 @@ suite('Disk File Service', () => {
|
|||
assert.ok(!error);
|
||||
});
|
||||
|
||||
test('watch - file', done => {
|
||||
const runWatchTests = isLinux;
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - file', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
||||
|
@ -1705,11 +1707,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50);
|
||||
});
|
||||
|
||||
test('watch - file symbolic link', async done => {
|
||||
if (isWindows) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - file symbolic link', async done => {
|
||||
const toWatch = URI.file(join(testDir, 'lorem.txt-linked'));
|
||||
await symlink(join(testDir, 'lorem.txt'), toWatch.fsPath);
|
||||
|
||||
|
@ -1718,11 +1716,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes'), 50);
|
||||
});
|
||||
|
||||
test('watch - file - multiple writes', done => {
|
||||
if (isWindows) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - file - multiple writes', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
||||
|
@ -1733,7 +1727,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(toWatch.fsPath, 'Changes 3'), 20);
|
||||
});
|
||||
|
||||
test('watch - file - delete file', done => {
|
||||
(runWatchTests ? test : test.skip)('watch - file - delete file', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
||||
|
@ -1742,11 +1736,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => unlinkSync(toWatch.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - file - rename file', done => {
|
||||
if (isWindows) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - file - rename file', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
const toWatchRenamed = URI.file(join(testDir, 'index-watch1-renamed.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
@ -1756,7 +1746,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - file - rename file (different case)', done => {
|
||||
(runWatchTests ? test : test.skip)('watch - file - rename file (different case)', done => {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch1.html'));
|
||||
const toWatchRenamed = URI.file(join(testDir, 'INDEX-watch1.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
@ -1770,7 +1760,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => renameSync(toWatch.fsPath, toWatchRenamed.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - file (atomic save)', function (done) {
|
||||
(runWatchTests ? test : test.skip)('watch - file (atomic save)', function (done) {
|
||||
const toWatch = URI.file(join(testDir, 'index-watch2.html'));
|
||||
writeFileSync(toWatch.fsPath, 'Init');
|
||||
|
||||
|
@ -1786,11 +1776,7 @@ suite('Disk File Service', () => {
|
|||
}, 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - change file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - change file', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch3'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1802,11 +1788,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - add file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - add file', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch4'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1817,11 +1799,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - delete file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete file', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch5'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1833,11 +1811,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => unlinkSync(file.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - add folder', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - add folder', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch6'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1848,11 +1822,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => mkdirSync(folder.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - delete folder', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - delete folder', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch7'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1864,11 +1834,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => rimrafSync(folder.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - symbolic link - change file', async done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests && !isWindows /* symbolic links not reliable on windows */ ? test : test.skip)('watch - folder (non recursive) - symbolic link - change file', async done => {
|
||||
const watchDir = URI.file(join(testDir, 'deep-link'));
|
||||
await symlink(join(testDir, 'deep'), watchDir.fsPath);
|
||||
|
||||
|
@ -1880,11 +1846,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => writeFileSync(file.fsPath, 'Changes'), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - rename file', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests ? test : test.skip)('watch - folder (non recursive) - rename file', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch8'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
@ -1898,11 +1860,7 @@ suite('Disk File Service', () => {
|
|||
setTimeout(() => renameSync(file.fsPath, fileRenamed.fsPath), 50);
|
||||
});
|
||||
|
||||
test('watch - folder (non recursive) - rename file (different case)', done => {
|
||||
if (!isLinux) {
|
||||
return done(); // watch tests are flaky on other platforms
|
||||
}
|
||||
|
||||
(runWatchTests && isLinux /* this test requires a case sensitive file system */ ? test : test.skip)('watch - folder (non recursive) - rename file (different case)', done => {
|
||||
const watchDir = URI.file(join(testDir, 'watch8'));
|
||||
mkdirSync(watchDir.fsPath);
|
||||
|
||||
|
|
|
@ -38,4 +38,10 @@ export class ProductService implements IProductService {
|
|||
get settingsSearchBuildId(): number | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchBuildId : undefined; }
|
||||
|
||||
get settingsSearchUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.settingsSearchUrl : undefined; }
|
||||
|
||||
get experimentsUrl(): string | undefined { return this.productConfiguration ? this.productConfiguration.experimentsUrl : undefined; }
|
||||
|
||||
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return this.productConfiguration ? this.productConfiguration.extensionKeywords : undefined; }
|
||||
|
||||
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return this.productConfiguration ? this.productConfiguration.extensionAllowedBadgeProviders : undefined; }
|
||||
}
|
|
@ -33,6 +33,10 @@ export interface IProductService {
|
|||
|
||||
readonly settingsSearchBuildId?: number;
|
||||
readonly settingsSearchUrl?: string;
|
||||
|
||||
readonly experimentsUrl?: string;
|
||||
readonly extensionKeywords?: { [extension: string]: readonly string[]; };
|
||||
readonly extensionAllowedBadgeProviders?: readonly string[];
|
||||
}
|
||||
|
||||
export interface IProductConfiguration {
|
||||
|
|
|
@ -33,4 +33,10 @@ export class ProductService implements IProductService {
|
|||
get settingsSearchBuildId(): number | undefined { return product.settingsSearchBuildId; }
|
||||
|
||||
get settingsSearchUrl(): string | undefined { return product.settingsSearchUrl; }
|
||||
|
||||
get experimentsUrl(): string | undefined { return product.experimentsUrl; }
|
||||
|
||||
get extensionKeywords(): { [extension: string]: readonly string[]; } | undefined { return product.extensionKeywords; }
|
||||
|
||||
get extensionAllowedBadgeProviders(): readonly string[] | undefined { return product.extensionAllowedBadgeProviders; }
|
||||
}
|
|
@ -12,22 +12,24 @@ import { VSBufferReadableStream, streamToBuffer } from 'vs/base/common/buffer';
|
|||
|
||||
export const IRequestService = createDecorator<IRequestService>('requestService');
|
||||
|
||||
export interface IHeaders {
|
||||
[header: string]: string;
|
||||
}
|
||||
|
||||
export interface IRequestOptions {
|
||||
type?: string;
|
||||
url?: string;
|
||||
user?: string;
|
||||
password?: string;
|
||||
headers?: any;
|
||||
headers?: IHeaders;
|
||||
timeout?: number;
|
||||
data?: string;
|
||||
followRedirects?: number;
|
||||
}
|
||||
|
||||
export interface IRequestContext {
|
||||
// req: http.ClientRequest;
|
||||
// res: http.ClientResponse;
|
||||
res: {
|
||||
headers: { [n: string]: string };
|
||||
headers: IHeaders;
|
||||
statusCode?: number;
|
||||
};
|
||||
stream: VSBufferReadableStream;
|
||||
|
|
51
src/vs/platform/request/common/requestIpc.ts
Normal 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) };
|
||||
}
|
||||
|
||||
}
|
|
@ -12,7 +12,7 @@ import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
|
||||
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey, currentSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
type Key = string;
|
||||
type Value = string;
|
||||
|
|
|
@ -38,3 +38,9 @@ export interface ITelemetryService {
|
|||
|
||||
isOptedIn: boolean;
|
||||
}
|
||||
|
||||
// Keys
|
||||
export const instanceStorageKey = 'telemetry.instanceId';
|
||||
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
|
||||
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
|
||||
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
|
|
@ -19,6 +19,7 @@ export interface ITelemetryServiceConfig {
|
|||
appender: ITelemetryAppender;
|
||||
commonProperties?: Promise<{ [name: string]: any }>;
|
||||
piiPaths?: string[];
|
||||
trueMachineId?: string;
|
||||
}
|
||||
|
||||
export class TelemetryService implements ITelemetryService {
|
||||
|
@ -74,6 +75,15 @@ export class TelemetryService implements ITelemetryService {
|
|||
}
|
||||
*/
|
||||
this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId });
|
||||
|
||||
if (config.trueMachineId) {
|
||||
/* __GDPR__
|
||||
"machineIdDisambiguation" : {
|
||||
"correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId });
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,11 +5,7 @@
|
|||
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { resolveCommonProperties } from 'vs/platform/telemetry/node/commonProperties';
|
||||
|
||||
export const instanceStorageKey = 'telemetry.instanceId';
|
||||
export const currentSessionDateStorageKey = 'telemetry.currentSessionDate';
|
||||
export const firstSessionDateStorageKey = 'telemetry.firstSessionDate';
|
||||
export const lastSessionDateStorageKey = 'telemetry.lastSessionDate';
|
||||
import { instanceStorageKey, firstSessionDateStorageKey, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> {
|
||||
const result = await resolveCommonProperties(commit, version, machineId, installSourcePath);
|
||||
|
|
5
src/vs/vscode.proposed.d.ts
vendored
|
@ -1084,8 +1084,11 @@ declare module 'vscode' {
|
|||
|
||||
/**
|
||||
* Implement to handle when the terminal is ready to start firing events.
|
||||
*
|
||||
* @param initialDimensions The dimensions of the terminal, this will be undefined if the
|
||||
* terminal panel has not been opened before this is called.
|
||||
*/
|
||||
start?(): void;
|
||||
start?(initialDimensions: TerminalDimensions | undefined): void;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
|
|
@ -88,7 +88,7 @@ export class MainThreadEditorInsets implements MainThreadEditorInsetsShape {
|
|||
|
||||
const disposables = new DisposableStore();
|
||||
|
||||
const webview = this._webviewService.createWebview({
|
||||
const webview = this._webviewService.createWebview('' + handle, {
|
||||
enableFindWidget: false,
|
||||
allowSvgs: false,
|
||||
extension: { id: extensionId, location: URI.revive(extensionLocation) }
|
||||
|
|
|
@ -4,8 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { StopWatch } from 'vs/base/common/stopwatch';
|
||||
|
@ -48,7 +48,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(proxy => this._onTerminalRequestVirtualProcess(proxy)));
|
||||
this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(e => this._onTerminalRequestVirtualProcess(e)));
|
||||
this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null)));
|
||||
this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title)));
|
||||
this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed)));
|
||||
|
@ -244,12 +244,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
return;
|
||||
}
|
||||
|
||||
const ready = this._terminalProcessesReady[request.proxy.terminalId];
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady[proxy.terminalId];
|
||||
if (ready) {
|
||||
ready(request.proxy);
|
||||
delete this._terminalProcessesReady[request.proxy.terminalId];
|
||||
ready(proxy);
|
||||
delete this._terminalProcessesReady[proxy.terminalId];
|
||||
} else {
|
||||
this._terminalProcesses[request.proxy.terminalId] = Promise.resolve(request.proxy);
|
||||
this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy);
|
||||
}
|
||||
const shellLaunchConfigDto: ShellLaunchConfigDto = {
|
||||
name: request.shellLaunchConfig.name,
|
||||
|
@ -258,16 +259,17 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
cwd: request.shellLaunchConfig.cwd,
|
||||
env: request.shellLaunchConfig.env
|
||||
};
|
||||
this._proxy.$createProcess(request.proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||
request.proxy.onInput(data => this._proxy.$acceptProcessInput(request.proxy.terminalId, data));
|
||||
request.proxy.onResize(dimensions => this._proxy.$acceptProcessResize(request.proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||
request.proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(request.proxy.terminalId, immediate));
|
||||
request.proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(request.proxy.terminalId));
|
||||
request.proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(request.proxy.terminalId));
|
||||
request.proxy.onRequestLatency(() => this._onRequestLatency(request.proxy.terminalId));
|
||||
this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed);
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
|
||||
proxy.onRequestInitialCwd(() => this._proxy.$acceptProcessRequestInitialCwd(proxy.terminalId));
|
||||
proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId));
|
||||
}
|
||||
|
||||
private _onTerminalRequestVirtualProcess(proxy: ITerminalProcessExtHostProxy): void {
|
||||
private _onTerminalRequestVirtualProcess(request: ITerminalVirtualProcessRequest): void {
|
||||
const proxy = request.proxy;
|
||||
const ready = this._terminalProcessesReady[proxy.terminalId];
|
||||
if (!ready) {
|
||||
this._terminalProcesses[proxy.terminalId] = Promise.resolve(proxy);
|
||||
|
@ -278,6 +280,11 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
|
|||
|
||||
// Note that onReisze is not being listened to here as it needs to fire when max dimensions
|
||||
// change, excluding the dimension override
|
||||
const initialDimensions: ITerminalDimensionsDto | undefined = request.cols && request.rows ? {
|
||||
columns: request.cols,
|
||||
rows: request.rows
|
||||
} : undefined;
|
||||
this._proxy.$startVirtualProcess(proxy.terminalId, initialDimensions);
|
||||
proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data));
|
||||
proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate));
|
||||
proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId));
|
||||
|
|
|
@ -93,7 +93,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||
mainThreadShowOptions.group = viewColumnToEditorGroup(this._editorGroupService, showOptions.viewColumn);
|
||||
}
|
||||
|
||||
const webview = this._webviewEditorService.createWebview(this.getInternalWebviewId(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
|
||||
const webview = this._webviewEditorService.createWebview(handle, this.getInternalWebviewViewType(viewType), title, mainThreadShowOptions, reviveWebviewOptions(options), {
|
||||
location: URI.revive(extensionLocation),
|
||||
id: extensionId
|
||||
}, this.createWebviewEventDelegate(handle)) as WebviewEditorInput<MainThreadWebviewState>;
|
||||
|
@ -212,7 +212,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
|||
this._revivers.delete(viewType);
|
||||
}
|
||||
|
||||
private getInternalWebviewId(viewType: string): string {
|
||||
private getInternalWebviewViewType(viewType: string): string {
|
||||
return `mainThreadWebview-${viewType}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -1135,6 +1135,11 @@ export interface IShellAndArgsDto {
|
|||
args: string[] | string | undefined;
|
||||
}
|
||||
|
||||
export interface ITerminalDimensionsDto {
|
||||
columns: number;
|
||||
rows: number;
|
||||
}
|
||||
|
||||
export interface ExtHostTerminalServiceShape {
|
||||
$acceptTerminalClosed(id: number): void;
|
||||
$acceptTerminalOpened(id: number, name: string): void;
|
||||
|
@ -1146,6 +1151,7 @@ export interface ExtHostTerminalServiceShape {
|
|||
$acceptTerminalDimensions(id: number, cols: number, rows: number): void;
|
||||
$acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void;
|
||||
$createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void;
|
||||
$startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void;
|
||||
$acceptProcessInput(id: number, data: string): void;
|
||||
$acceptProcessResize(id: number, cols: number, rows: number): void;
|
||||
$acceptProcessShutdown(id: number, immediate: boolean): void;
|
||||
|
|
|
@ -40,7 +40,7 @@ export class ExtHostWebview implements vscode.Webview {
|
|||
}
|
||||
|
||||
public get cspSource(): string {
|
||||
return this._initData.webviewCspSource;
|
||||
return this._initData.webviewCspSource.replace('{{uuid}}', this._handle);
|
||||
}
|
||||
|
||||
public get html(): string {
|
||||
|
|
|
@ -10,7 +10,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
|
|||
import * as platform from 'vs/base/common/platform';
|
||||
import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostTerminalServiceShape, MainContext, MainThreadTerminalServiceShape, IMainContext, ShellLaunchConfigDto, IShellDefinitionDto, IShellAndArgsDto, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { EXT_HOST_CREATION_DELAY, IShellLaunchConfig, ITerminalEnvironment, ITerminalChildProcess, ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal';
|
||||
|
@ -329,10 +329,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal {
|
||||
const terminal = new ExtHostTerminal(this._proxy, options.name);
|
||||
const p = new ExtHostVirtualProcess(options.virtualProcess);
|
||||
terminal.createVirtualProcess().then(() => {
|
||||
this._setupExtHostProcessListeners(terminal._id, p);
|
||||
p.startSendingEvents();
|
||||
});
|
||||
terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p));
|
||||
this._terminals.push(terminal);
|
||||
return terminal;
|
||||
}
|
||||
|
@ -344,7 +341,6 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
}
|
||||
const p = new ExtHostVirtualProcess(virtualProcess);
|
||||
this._setupExtHostProcessListeners(id, p);
|
||||
p.startSendingEvents();
|
||||
}
|
||||
|
||||
public createTerminalRenderer(name: string): vscode.TerminalRenderer {
|
||||
|
@ -585,6 +581,10 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape {
|
|||
this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService));
|
||||
}
|
||||
|
||||
public $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
(this._terminalProcesses[id] as ExtHostVirtualProcess).startSendingEvents(initialDimensions);
|
||||
}
|
||||
|
||||
private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void {
|
||||
p.onProcessReady((e: { pid: number, cwd: string }) => this._proxy.$sendProcessReady(id, e.pid, e.cwd));
|
||||
p.onProcessTitleChanged(title => this._proxy.$sendProcessTitle(id, title));
|
||||
|
@ -779,7 +779,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
|
|||
return Promise.resolve(0);
|
||||
}
|
||||
|
||||
startSendingEvents(): void {
|
||||
startSendingEvents(initialDimensions: ITerminalDimensionsDto | undefined): void {
|
||||
// Flush all buffered events
|
||||
this._queuedEvents.forEach(e => (<any>e.emitter.fire)(e.data));
|
||||
this._queuedEvents = [];
|
||||
|
@ -798,7 +798,7 @@ class ExtHostVirtualProcess implements ITerminalChildProcess {
|
|||
}
|
||||
|
||||
if (this._virtualProcess.start) {
|
||||
this._virtualProcess.start();
|
||||
this._virtualProcess.start(initialDimensions);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,6 +40,9 @@ import { joinPath } from 'vs/base/common/resources';
|
|||
import { BrowserStorageService } from 'vs/platform/storage/browser/storageService';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { getThemeTypeSelector, DARK, HIGH_CONTRAST, LIGHT } from 'vs/platform/theme/common/themeService';
|
||||
import { IRequestService } from 'vs/platform/request/common/request';
|
||||
import { RequestService } from 'vs/workbench/services/request/browser/requestService';
|
||||
import { InMemoryUserDataProvider } from 'vs/workbench/services/userData/common/inMemoryUserDataProvider';
|
||||
|
||||
class CodeRendererMain extends Disposable {
|
||||
|
||||
|
@ -155,12 +158,14 @@ class CodeRendererMain extends Disposable {
|
|||
}
|
||||
}
|
||||
|
||||
// User Data Provider
|
||||
if (userDataProvider) {
|
||||
fileService.registerProvider(Schemas.userData, userDataProvider);
|
||||
if (!userDataProvider) {
|
||||
userDataProvider = this._register(new InMemoryUserDataProvider());
|
||||
}
|
||||
|
||||
const services = await Promise.all([
|
||||
// User Data Provider
|
||||
fileService.registerProvider(Schemas.userData, userDataProvider);
|
||||
|
||||
const [configurationService, storageService] = await Promise.all([
|
||||
this.createWorkspaceService(payload, environmentService, fileService, remoteAgentService, logService).then(service => {
|
||||
|
||||
// Workspace
|
||||
|
@ -181,7 +186,10 @@ class CodeRendererMain extends Disposable {
|
|||
})
|
||||
]);
|
||||
|
||||
return { serviceCollection, logService, storageService: services[1] };
|
||||
// Request Service
|
||||
serviceCollection.set(IRequestService, new RequestService(this.configuration.requestHandler, remoteAgentService, configurationService, logService));
|
||||
|
||||
return { serviceCollection, logService, storageService };
|
||||
}
|
||||
|
||||
private async createStorageService(payload: IWorkspaceInitializationPayload, environmentService: IWorkbenchEnvironmentService, fileService: IFileService, logService: ILogService): Promise<BrowserStorageService> {
|
||||
|
|
|
@ -11,9 +11,8 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'
|
|||
// tslint:disable-next-line: import-patterns no-standalone-editor
|
||||
import { IDownloadService } from 'vs/platform/download/common/download';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { IPager } from 'vs/base/common/paging';
|
||||
import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IGalleryExtension, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions';
|
||||
import { IURLHandler, IURLService } from 'vs/platform/url/common/url';
|
||||
import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ConsoleLogService, ILogService } from 'vs/platform/log/common/log';
|
||||
|
@ -29,7 +28,6 @@ import { ITunnelService } from 'vs/platform/remote/common/tunnel';
|
|||
import { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug';
|
||||
import { IRemoteConsoleLog } from 'vs/base/common/console';
|
||||
// tslint:disable-next-line: import-patterns
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { IExtensionsWorkbenchService, IExtension as IExtension2 } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
|
||||
import { addDisposableListener, EventType } from 'vs/base/browser/dom';
|
||||
|
@ -41,6 +39,8 @@ import { ParsedArgs } from 'vs/platform/environment/common/environment';
|
|||
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
|
||||
import { IProcessEnvironment } from 'vs/base/common/platform';
|
||||
import { toStoreData, restoreRecentlyOpened } from 'vs/platform/history/common/historyStorage';
|
||||
// tslint:disable-next-line: import-patterns
|
||||
import { IExperimentService, IExperiment, ExperimentActionType, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
|
||||
//#region Download
|
||||
|
||||
|
@ -58,74 +58,6 @@ registerSingleton(IDownloadService, SimpleDownloadService, true);
|
|||
|
||||
//#endregion
|
||||
|
||||
//#region Extension Gallery
|
||||
|
||||
export class SimpleExtensionGalleryService implements IExtensionGalleryService {
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
isEnabled(): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
query(token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
query(options: IQueryOptions, token: CancellationToken): Promise<IPager<IGalleryExtension>>;
|
||||
query(arg1: any, arg2?: any): Promise<IPager<IGalleryExtension>> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
download(extension: IGalleryExtension, operation: InstallOperation): Promise<string> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
reportStatistic(publisher: string, name: string, version: string, type: StatisticType): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getReadme(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getManifest(extension: IGalleryExtension, token: CancellationToken): Promise<IExtensionManifest> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getChangelog(extension: IGalleryExtension, token: CancellationToken): Promise<string> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getCoreTranslation(extension: IGalleryExtension, languageId: string): Promise<ITranslation> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getAllVersions(extension: IGalleryExtension, compatible: boolean): Promise<IGalleryExtensionVersion[]> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
getExtensionsReport(): Promise<IReportedExtension[]> {
|
||||
// @ts-ignore
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
getCompatibleExtension(extension: IGalleryExtension): Promise<IGalleryExtension>;
|
||||
getCompatibleExtension(id: IExtensionIdentifier, version?: string): Promise<IGalleryExtension>;
|
||||
getCompatibleExtension(id: any, version?: any) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
}
|
||||
|
||||
registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, true);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#endregion IExtensionsWorkbenchService
|
||||
export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService {
|
||||
_serviceBrand: any;
|
||||
|
@ -1066,3 +998,34 @@ class SimpleTunnelService implements ITunnelService {
|
|||
registerSingleton(ITunnelService, SimpleTunnelService);
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region experiments
|
||||
|
||||
class ExperimentService implements IExperimentService {
|
||||
_serviceBrand: any;
|
||||
|
||||
async getExperimentById(id: string): Promise<IExperiment> {
|
||||
return {
|
||||
enabled: false,
|
||||
id: '',
|
||||
state: ExperimentState.NoRun
|
||||
};
|
||||
}
|
||||
|
||||
async getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
async getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]> {
|
||||
return [];
|
||||
}
|
||||
|
||||
markAsCompleted(experimentId: string): void { }
|
||||
|
||||
onExperimentEnabled: Event<IExperiment> = Event.None;
|
||||
|
||||
}
|
||||
|
||||
registerSingleton(IExperimentService, ExperimentService);
|
||||
|
||||
//#endregion
|
||||
|
|
|
@ -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');
|
|
@ -3,12 +3,9 @@
|
|||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import product from 'vs/platform/product/node/product';
|
||||
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
|
@ -21,8 +18,9 @@ import { ITextFileService, StateChange } from 'vs/workbench/services/textfile/co
|
|||
import { WorkspaceStats } from 'vs/workbench/contrib/stats/electron-browser/workspaceStats';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { distinct } from 'vs/base/common/arrays';
|
||||
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExperimentState, IExperimentAction, IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { IProductService } from 'vs/platform/product/common/product';
|
||||
|
||||
interface IExperimentStorageState {
|
||||
enabled: boolean;
|
||||
|
@ -31,13 +29,6 @@ interface IExperimentStorageState {
|
|||
lastEditedDate?: string;
|
||||
}
|
||||
|
||||
export const enum ExperimentState {
|
||||
Evaluating,
|
||||
NoRun,
|
||||
Run,
|
||||
Complete
|
||||
}
|
||||
|
||||
interface IRawExperiment {
|
||||
id: string;
|
||||
enabled?: boolean;
|
||||
|
@ -64,51 +55,6 @@ interface IRawExperiment {
|
|||
action?: IExperimentAction;
|
||||
}
|
||||
|
||||
interface IExperimentAction {
|
||||
type: ExperimentActionType;
|
||||
properties: any;
|
||||
}
|
||||
|
||||
export enum ExperimentActionType {
|
||||
Custom = 'Custom',
|
||||
Prompt = 'Prompt',
|
||||
AddToRecommendations = 'AddToRecommendations',
|
||||
ExtensionSearchResults = 'ExtensionSearchResults'
|
||||
}
|
||||
|
||||
export type LocalizedPromptText = { [locale: string]: string; };
|
||||
|
||||
export interface IExperimentActionPromptProperties {
|
||||
promptText: string | LocalizedPromptText;
|
||||
commands: IExperimentActionPromptCommand[];
|
||||
}
|
||||
|
||||
export interface IExperimentActionPromptCommand {
|
||||
text: string | { [key: string]: string };
|
||||
externalLink?: string;
|
||||
curatedExtensionsKey?: string;
|
||||
curatedExtensionsList?: string[];
|
||||
}
|
||||
|
||||
export interface IExperiment {
|
||||
id: string;
|
||||
enabled: boolean;
|
||||
state: ExperimentState;
|
||||
action?: IExperimentAction;
|
||||
}
|
||||
|
||||
export interface IExperimentService {
|
||||
_serviceBrand: any;
|
||||
getExperimentById(id: string): Promise<IExperiment>;
|
||||
getExperimentsByType(type: ExperimentActionType): Promise<IExperiment[]>;
|
||||
getCuratedExtensionsList(curatedExtensionsKey: string): Promise<string[]>;
|
||||
markAsCompleted(experimentId: string): void;
|
||||
|
||||
onExperimentEnabled: Event<IExperiment>;
|
||||
}
|
||||
|
||||
export const IExperimentService = createDecorator<IExperimentService>('experimentService');
|
||||
|
||||
export class ExperimentService extends Disposable implements IExperimentService {
|
||||
_serviceBrand: any;
|
||||
private _experiments: IExperiment[] = [];
|
||||
|
@ -127,7 +73,8 @@ export class ExperimentService extends Disposable implements IExperimentService
|
|||
@ITelemetryService private readonly telemetryService: ITelemetryService,
|
||||
@ILifecycleService private readonly lifecycleService: ILifecycleService,
|
||||
@IRequestService private readonly requestService: IRequestService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService,
|
||||
@IProductService private readonly productService: IProductService
|
||||
) {
|
||||
super();
|
||||
|
||||
|
@ -171,10 +118,10 @@ export class ExperimentService extends Disposable implements IExperimentService
|
|||
}
|
||||
|
||||
protected getExperiments(): Promise<IRawExperiment[]> {
|
||||
if (!product.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
|
||||
if (!this.productService.experimentsUrl || this.configurationService.getValue('workbench.enableExperiments') === false) {
|
||||
return Promise.resolve([]);
|
||||
}
|
||||
return this.requestService.request({ type: 'GET', url: product.experimentsUrl }, CancellationToken.None).then(context => {
|
||||
return this.requestService.request({ type: 'GET', url: this.productService.experimentsUrl }, CancellationToken.None).then(context => {
|
||||
if (context.res.statusCode !== 200) {
|
||||
return Promise.resolve(null);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
|
||||
import { INotificationService, Severity, IPromptChoice } from 'vs/platform/notification/common/notification';
|
||||
import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActionPromptProperties, IExperimentActionPromptCommand, ExperimentState } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||
import { IExperimentService, ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { IExperimentService } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions';
|
||||
import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
|
|
|
@ -4,7 +4,8 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'assert';
|
||||
import { ExperimentService, ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { ExperimentActionType, ExperimentState, IExperiment } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { ExperimentService } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
||||
|
@ -17,7 +18,7 @@ import { Emitter } from 'vs/base/common/event';
|
|||
import { TestExtensionEnablementService } from 'vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test';
|
||||
import { URLService } from 'vs/platform/url/common/urlService';
|
||||
import { IURLService } from 'vs/platform/url/common/url';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { ITelemetryService, lastSessionDateStorageKey } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { TestConfigurationService } from 'vs/platform/configuration/test/common/testConfigurationService';
|
||||
|
@ -25,7 +26,6 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
|||
import { assign } from 'vs/base/common/objects';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { lastSessionDateStorageKey } from 'vs/platform/telemetry/node/workbenchCommonProperties';
|
||||
import { getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { ExtensionType } from 'vs/platform/extensions/common/extensions';
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag
|
|||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils';
|
||||
import { ExperimentalPrompts } from 'vs/workbench/contrib/experiments/electron-browser/experimentalPrompt';
|
||||
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { ExperimentActionType, ExperimentState, IExperiment, IExperimentActionPromptProperties, IExperimentService, LocalizedPromptText } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { TestExperimentService } from 'vs/workbench/contrib/experiments/test/electron-browser/experimentService.test';
|
||||
import { TestLifecycleService } from 'vs/workbench/test/workbenchTestServices';
|
||||
|
||||
|
|
|
@ -25,11 +25,10 @@ import { IExtensionManifest, IKeyBinding, IView, IViewContainer, ExtensionType }
|
|||
import { ResolvedKeybinding, KeyMod, KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, IExtension, ExtensionContainers } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { RatingsWidget, InstallCountWidget, RemoteBadgeWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||
import { EditorOptions } from 'vs/workbench/common/editor';
|
||||
import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement';
|
||||
import { CombinedInstallAction, UpdateAction, ExtensionEditorDropDownAction, ReloadAction, MaliciousStatusLabelAction, IgnoreExtensionRecommendationAction, UndoIgnoreExtensionRecommendationAction, EnableDropDownAction, DisableDropDownAction, StatusLabelAction, SetFileIconThemeAction, SetColorThemeAction, RemoteInstallAction, DisabledLabelAction, SystemDisabledWarningAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import { IOpenerService } from 'vs/platform/opener/common/opener';
|
||||
|
@ -44,7 +43,7 @@ import { assign } from 'vs/base/common/objects';
|
|||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { ExtensionsTree, ExtensionData } from 'vs/workbench/contrib/extensions/browser/extensionsViewer';
|
||||
import { ShowCurrentReleaseNotesAction } from 'vs/workbench/contrib/update/electron-browser/update';
|
||||
import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update';
|
||||
import { KeybindingParser } from 'vs/base/common/keybindingParser';
|
||||
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
@ -52,6 +51,7 @@ import { getDefaultValue } from 'vs/platform/configuration/common/configurationR
|
|||
import { isUndefined } from 'vs/base/common/types';
|
||||
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview';
|
||||
|
||||
function renderBody(body: string): string {
|
||||
const styleSheetPath = require.toUrl('./media/markdown.css').replace('file://', 'vscode-resource://');
|
||||
|
@ -194,8 +194,8 @@ export class ExtensionEditor extends BaseEditor {
|
|||
@IExtensionTipsService private readonly extensionTipsService: IExtensionTipsService,
|
||||
@IStorageService storageService: IStorageService,
|
||||
@IExtensionService private readonly extensionService: IExtensionService,
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService
|
||||
|
||||
@IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService,
|
||||
@IWebviewService private readonly webviewService: IWebviewService
|
||||
) {
|
||||
super(ExtensionEditor.ID, telemetryService, themeService, storageService);
|
||||
this.extensionReadme = null;
|
||||
|
@ -490,8 +490,8 @@ export class ExtensionEditor extends BaseEditor {
|
|||
}
|
||||
|
||||
showFind(): void {
|
||||
if (this.activeElement instanceof WebviewElement) {
|
||||
this.activeElement.showFind();
|
||||
if (this.activeElement && (<Webview>this.activeElement).showFind) {
|
||||
(<Webview>this.activeElement).showFind();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -537,7 +537,7 @@ export class ExtensionEditor extends BaseEditor {
|
|||
.then(renderBody)
|
||||
.then(removeEmbeddedSVGs)
|
||||
.then(body => {
|
||||
const webviewElement = this.instantiationService.createInstance(WebviewElement,
|
||||
const webviewElement = this.webviewService.createWebview('extensionEditor',
|
||||
{
|
||||
enableFindWidget: true,
|
||||
},
|
||||
|
@ -558,7 +558,7 @@ export class ExtensionEditor extends BaseEditor {
|
|||
return;
|
||||
}
|
||||
// Whitelist supported schemes for links
|
||||
if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesAction.ID)) {
|
||||
if (['http', 'https', 'mailto'].indexOf(link.scheme) >= 0 || (link.scheme === 'command' && link.path === ShowCurrentReleaseNotesActionId)) {
|
||||
this.openerService.open(link);
|
||||
}
|
||||
}, null, this.contentDisposables));
|
|
@ -13,9 +13,9 @@ import { IPagedRenderer } from 'vs/base/browser/ui/list/listPaging';
|
|||
import { Event } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IExtension, ExtensionContainers, ExtensionState, IExtensionsWorkbenchService } from 'vs/workbench/contrib/extensions/common/extensions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { InstallAction, UpdateAction, ManageExtensionAction, ReloadAction, MaliciousStatusLabelAction, ExtensionActionViewItem, StatusLabelAction, RemoteInstallAction, SystemDisabledWarningAction, DisabledLabelAction, LocalInstallAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/electron-browser/extensionsWidgets';
|
||||
import { Label, RatingsWidget, InstallCountWidget, RecommendationWidget, RemoteBadgeWidget, TooltipWidget } from 'vs/workbench/contrib/extensions/browser/extensionsWidgets';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { INotificationService } from 'vs/platform/notification/common/notification';
|
|
@ -8,7 +8,7 @@ import { localize } from 'vs/nls';
|
|||
import { timeout, Delayer } from 'vs/base/common/async';
|
||||
import { isPromiseCanceledError } from 'vs/base/common/errors';
|
||||
import { IWorkbenchContribution } from 'vs/workbench/common/contributions';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Event as EventOf, Emitter } from 'vs/base/common/event';
|
||||
import { IAction } from 'vs/base/common/actions';
|
||||
import { Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
|
@ -23,10 +23,10 @@ import {
|
|||
ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction,
|
||||
ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction,
|
||||
EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction
|
||||
} from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
} from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IExtensionManagementService, IExtensionManagementServerService, IExtensionManagementServer, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews';
|
||||
import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from 'vs/workbench/contrib/extensions/browser/extensionsViews';
|
||||
import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions';
|
||||
import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress';
|
||||
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
|
@ -339,7 +339,6 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
private extensionsBox: HTMLElement;
|
||||
private primaryActions: IAction[];
|
||||
private secondaryActions: IAction[] | null;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly searchViewletState: MementoObject;
|
||||
|
||||
constructor(
|
||||
|
@ -374,14 +373,14 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
this.recommendedExtensionsContextKey = RecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey = DefaultRecommendedExtensionsContext.bindTo(contextKeyService);
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
this.disposables.push(this.viewletService.onDidViewletOpen(this.onViewletOpen, this, this.disposables));
|
||||
this._register(this.viewletService.onDidViewletOpen(this.onViewletOpen, this));
|
||||
this.searchViewletState = this.getMemento(StorageScope.WORKSPACE);
|
||||
|
||||
this.extensionManagementService.getInstalled(ExtensionType.User).then(result => {
|
||||
this.hasInstalledExtensionsContextKey.set(result.length > 0);
|
||||
});
|
||||
|
||||
this.configurationService.onDidChangeConfiguration(e => {
|
||||
this._register(this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectsConfiguration(AutoUpdateConfigurationKey)) {
|
||||
this.secondaryActions = null;
|
||||
this.updateTitleArea();
|
||||
|
@ -389,7 +388,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
if (e.affectedKeys.indexOf(ShowRecommendationsOnlyOnDemandKey) > -1) {
|
||||
this.defaultRecommendedExtensionsContextKey.set(!this.configurationService.getValue<boolean>(ShowRecommendationsOnlyOnDemandKey));
|
||||
}
|
||||
}, this, this.disposables);
|
||||
}, this));
|
||||
}
|
||||
|
||||
create(parent: HTMLElement): void {
|
||||
|
@ -401,7 +400,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
const placeholder = localize('searchExtensions', "Search Extensions in Marketplace");
|
||||
const searchValue = this.searchViewletState['query.value'] ? this.searchViewletState['query.value'] : '';
|
||||
|
||||
this.searchBox = this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, {
|
||||
this.searchBox = this._register(this.instantiationService.createInstance(SuggestEnabledInput, `${VIEWLET_ID}.searchbox`, header, {
|
||||
triggerCharacters: ['@'],
|
||||
sortKey: (item: string) => {
|
||||
if (item.indexOf(':') === -1) { return 'a'; }
|
||||
|
@ -410,24 +409,22 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
else { return 'd'; }
|
||||
},
|
||||
provideResults: (query: string) => Query.suggestions(query)
|
||||
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue });
|
||||
}, placeholder, 'extensions:searchinput', { placeholderText: placeholder, value: searchValue }));
|
||||
|
||||
if (this.searchBox.getValue()) {
|
||||
this.triggerSearch();
|
||||
}
|
||||
|
||||
this.disposables.push(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
|
||||
|
||||
this.disposables.push(this.searchBox);
|
||||
this._register(attachSuggestEnabledInputBoxStyler(this.searchBox, this.themeService));
|
||||
|
||||
const _searchChange = new Emitter<string>();
|
||||
this.onSearchChange = _searchChange.event;
|
||||
this.searchBox.onInputDidChange(() => {
|
||||
this._register(this.searchBox.onInputDidChange(() => {
|
||||
this.triggerSearch();
|
||||
_searchChange.fire(this.searchBox.getValue());
|
||||
}, this, this.disposables);
|
||||
}, this));
|
||||
|
||||
this.searchBox.onShouldFocusResults(() => this.focusListView(), this, this.disposables);
|
||||
this._register(this.searchBox.onShouldFocusResults(() => this.focusListView(), this));
|
||||
|
||||
this._register(this.onDidChangeVisibility(visible => {
|
||||
if (visible) {
|
||||
|
@ -614,52 +611,39 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio
|
|||
|
||||
this.notificationService.error(err);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
export class StatusUpdater implements IWorkbenchContribution {
|
||||
export class StatusUpdater extends Disposable implements IWorkbenchContribution {
|
||||
|
||||
private disposables: IDisposable[];
|
||||
private badgeHandle: IDisposable;
|
||||
private readonly badgeHandle = this._register(new MutableDisposable());
|
||||
|
||||
constructor(
|
||||
@IActivityService private readonly activityService: IActivityService,
|
||||
@IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService,
|
||||
@IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService
|
||||
) {
|
||||
extensionsWorkbenchService.onChange(this.onServiceChange, this, this.disposables);
|
||||
super();
|
||||
this._register(extensionsWorkbenchService.onChange(this.onServiceChange, this));
|
||||
}
|
||||
|
||||
private onServiceChange(): void {
|
||||
|
||||
dispose(this.badgeHandle);
|
||||
this.badgeHandle.clear();
|
||||
|
||||
if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) {
|
||||
this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge');
|
||||
this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge');
|
||||
return;
|
||||
}
|
||||
|
||||
const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0);
|
||||
if (outdated > 0) {
|
||||
const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n));
|
||||
this.badgeHandle = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge');
|
||||
this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, badge, 'extensions-badge count-badge');
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
dispose(this.badgeHandle);
|
||||
}
|
||||
}
|
||||
|
||||
export class MaliciousExtensionChecker implements IWorkbenchContribution {
|
||||
|
||||
private disposables: IDisposable[];
|
||||
|
||||
constructor(
|
||||
@IExtensionManagementService private readonly extensionsManagementService: IExtensionManagementService,
|
||||
@IWindowService private readonly windowService: IWindowService,
|
||||
|
@ -704,8 +688,4 @@ export class MaliciousExtensionChecker implements IWorkbenchContribution {
|
|||
}).then(() => undefined);
|
||||
}, err => this.logService.error(err));
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
|
@ -15,7 +15,7 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
|||
import { IContextMenuService } from 'vs/platform/contextview/browser/contextView';
|
||||
import { append, $, toggleClass } from 'vs/base/browser/dom';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/electron-browser/extensionsList';
|
||||
import { Delegate, Renderer, IExtensionsViewState } from 'vs/workbench/contrib/extensions/browser/extensionsList';
|
||||
import { IExtension, IExtensionsWorkbenchService, ExtensionState } from '../common/extensions';
|
||||
import { Query } from '../common/extensionQuery';
|
||||
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
|
||||
|
@ -27,14 +27,14 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
|
|||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge';
|
||||
import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar';
|
||||
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { WorkbenchPagedList } from 'vs/platform/list/browser/listService';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { INotificationService, Severity } from 'vs/platform/notification/common/notification';
|
||||
import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet';
|
||||
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
|
||||
import { distinct, coalesce } from 'vs/base/common/arrays';
|
||||
import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/electron-browser/experimentService';
|
||||
import { IExperimentService, IExperiment, ExperimentActionType } from 'vs/workbench/contrib/experiments/common/experimentService';
|
||||
import { alert } from 'vs/base/browser/ui/aria/aria';
|
||||
import { IListContextMenuEvent } from 'vs/base/browser/ui/list/list';
|
||||
import { createErrorWithActions } from 'vs/base/common/errorsWithActions';
|
|
@ -4,14 +4,14 @@
|
|||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import 'vs/css!./media/extensionsWidgets';
|
||||
import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { Disposable, toDisposable, DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtension, IExtensionsWorkbenchService, IExtensionContainer, ExtensionState } from '../common/extensions';
|
||||
import { append, $, addClass } from 'vs/base/browser/dom';
|
||||
import * as platform from 'vs/base/common/platform';
|
||||
import { localize } from 'vs/nls';
|
||||
import { IExtensionManagementServerService, IExtensionTipsService } from 'vs/platform/extensionManagement/common/extensionManagement';
|
||||
import { ILabelService } from 'vs/platform/label/common/label';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions';
|
||||
import { extensionButtonProminentBackground, extensionButtonProminentForeground, DisabledLabelAction, ReloadAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions';
|
||||
import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService';
|
||||
import { EXTENSION_BADGE_REMOTE_BACKGROUND, EXTENSION_BADGE_REMOTE_FOREGROUND } from 'vs/workbench/common/theme';
|
||||
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
@ -196,7 +196,7 @@ export class TooltipWidget extends ExtensionWidget {
|
|||
export class RecommendationWidget extends ExtensionWidget {
|
||||
|
||||
private element?: HTMLElement;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly disposables = this._register(new DisposableStore());
|
||||
|
||||
private _tooltip: string;
|
||||
get tooltip(): string { return this._tooltip; }
|
||||
|
@ -227,7 +227,7 @@ export class RecommendationWidget extends ExtensionWidget {
|
|||
this.parent.removeChild(this.element);
|
||||
}
|
||||
this.element = undefined;
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.disposables.clear();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
|
@ -256,8 +256,7 @@ export class RecommendationWidget extends ExtensionWidget {
|
|||
|
||||
export class RemoteBadgeWidget extends ExtensionWidget {
|
||||
|
||||
private remoteBadge: RemoteBadge | null;
|
||||
private disposables: IDisposable[] = [];
|
||||
private readonly remoteBadge = this._register(new MutableDisposable<RemoteBadge>());
|
||||
|
||||
private element: HTMLElement;
|
||||
|
||||
|
@ -274,12 +273,10 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
|||
}
|
||||
|
||||
private clear(): void {
|
||||
if (this.remoteBadge) {
|
||||
this.element.removeChild(this.remoteBadge.element);
|
||||
this.remoteBadge.dispose();
|
||||
if (this.remoteBadge.value) {
|
||||
this.element.removeChild(this.remoteBadge.value.element);
|
||||
}
|
||||
this.remoteBadge = null;
|
||||
this.disposables = dispose(this.disposables);
|
||||
this.remoteBadge.clear();
|
||||
}
|
||||
|
||||
render(): void {
|
||||
|
@ -288,17 +285,10 @@ export class RemoteBadgeWidget extends ExtensionWidget {
|
|||
return;
|
||||
}
|
||||
if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer) {
|
||||
this.remoteBadge = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
|
||||
append(this.element, this.remoteBadge.element);
|
||||
this.remoteBadge.value = this.instantiationService.createInstance(RemoteBadge, this.tooltip);
|
||||
append(this.element, this.remoteBadge.value.element);
|
||||
}
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
if (this.remoteBadge) {
|
||||
this.remoteBadge.dispose();
|
||||
}
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
class RemoteBadge extends Disposable {
|
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
Before Width: | Height: | Size: 474 B After Width: | Height: | Size: 474 B |
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 419 B |
Before Width: | Height: | Size: 484 B After Width: | Height: | Size: 484 B |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |
Before Width: | Height: | Size: 9.9 KiB After Width: | Height: | Size: 9.9 KiB |