mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-03-09 12:01:37 -04:00
Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028)
This commit is contained in:
4
build/azure-pipelines/darwin/build.sh
Executable file
4
build/azure-pipelines/darwin/build.sh
Executable file
@@ -0,0 +1,4 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
yarn gulp vscode-darwin-min
|
||||
yarn gulp upload-vscode-sourcemaps
|
||||
@@ -18,9 +18,15 @@ steps:
|
||||
password $(VSCODE_MIXIN_PASSWORD)
|
||||
EOF
|
||||
|
||||
git config user.email "vscode@microsoft.com"
|
||||
git config user.name "VSCode"
|
||||
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
|
||||
git fetch distro
|
||||
git merge $(node -p "require('./package.json').distro")
|
||||
|
||||
yarn
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" yarn gulp -- mixin
|
||||
yarn gulp -- hygiene
|
||||
yarn gulp mixin
|
||||
yarn gulp hygiene
|
||||
yarn monaco-compile-check
|
||||
node build/azure-pipelines/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
@@ -30,10 +36,7 @@ steps:
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
yarn gulp -- vscode-darwin-min
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
yarn gulp -- upload-vscode-sourcemaps
|
||||
./build/azure-pipelines/darwin/build.sh
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
@@ -43,6 +46,11 @@ steps:
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)/VSCode-darwin/$APP_NAME"
|
||||
displayName: Run unit tests
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
./scripts/test-integration.sh --build --tfs "Integration Tests"
|
||||
displayName: Run integration tests
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
pushd ../VSCode-darwin && zip -r -X -y ../VSCode-darwin.zip * && popd
|
||||
@@ -69,30 +77,12 @@ steps:
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
|
||||
# remove pkg from archive
|
||||
zip -d ../VSCode-darwin.zip "*.pkg"
|
||||
|
||||
# publish the build
|
||||
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
|
||||
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/azure-pipelines/common/publish.js \
|
||||
"$(VSCODE_QUALITY)" \
|
||||
darwin \
|
||||
archive \
|
||||
"VSCode-darwin-$(VSCODE_QUALITY).zip" \
|
||||
$VERSION \
|
||||
true \
|
||||
../VSCode-darwin.zip
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_MACOS)"
|
||||
|
||||
# upload configuration
|
||||
AZURE_STORAGE_ACCESS_KEY="$(AZURE_STORAGE_ACCESS_KEY)" \
|
||||
yarn gulp -- upload-vscode-configuration
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
|
||||
./build/azure-pipelines/darwin/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
|
||||
22
build/azure-pipelines/darwin/publish.sh
Executable file
22
build/azure-pipelines/darwin/publish.sh
Executable file
@@ -0,0 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
# remove pkg from archive
|
||||
zip -d ../VSCode-darwin.zip "*.pkg"
|
||||
|
||||
# publish the build
|
||||
PACKAGEJSON=`ls ../VSCode-darwin/*.app/Contents/Resources/app/package.json`
|
||||
VERSION=`node -p "require(\"$PACKAGEJSON\").version"`
|
||||
node build/azure-pipelines/common/publish.js \
|
||||
"$VSCODE_QUALITY" \
|
||||
darwin \
|
||||
archive \
|
||||
"VSCode-darwin-$VSCODE_QUALITY.zip" \
|
||||
$VERSION \
|
||||
true \
|
||||
../VSCode-darwin.zip
|
||||
|
||||
# publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_MACOS"
|
||||
|
||||
# upload configuration
|
||||
yarn gulp upload-vscode-configuration
|
||||
@@ -24,6 +24,7 @@ steps:
|
||||
|
||||
git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git"
|
||||
git fetch distro
|
||||
git push distro origin/master:refs/heads/master
|
||||
git merge $(node -p "require('./package.json').distro")
|
||||
|
||||
displayName: Merge Distro
|
||||
displayName: Sync & Merge Distro
|
||||
3
build/azure-pipelines/linux/build.sh
Executable file
3
build/azure-pipelines/linux/build.sh
Executable file
@@ -0,0 +1,3 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-min"
|
||||
@@ -22,87 +22,45 @@ steps:
|
||||
password $(VSCODE_MIXIN_PASSWORD)
|
||||
EOF
|
||||
|
||||
git config user.email "vscode@microsoft.com"
|
||||
git config user.name "VSCode"
|
||||
git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git"
|
||||
git fetch distro
|
||||
git merge $(node -p "require('./package.json').distro")
|
||||
|
||||
CHILD_CONCURRENCY=1 yarn
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- mixin
|
||||
npm run gulp -- hygiene
|
||||
npm run monaco-compile-check
|
||||
yarn gulp mixin
|
||||
yarn gulp hygiene
|
||||
yarn monaco-compile-check
|
||||
node build/azure-pipelines/common/installDistro.js
|
||||
node build/lib/builtInExtensions.js
|
||||
displayName: Prepare build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" npm run gulp -- vscode-linux-$(VSCODE_ARCH)-min
|
||||
name: build
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
./build/azure-pipelines/linux/build.sh
|
||||
displayName: Build
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
npm run gulp -- "electron-$(VSCODE_ARCH)"
|
||||
yarn gulp "electron-$(VSCODE_ARCH)"
|
||||
|
||||
# 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)"
|
||||
name: test
|
||||
displayName: Run unit tests
|
||||
|
||||
- script: |
|
||||
set -e
|
||||
REPO="$(pwd)"
|
||||
ROOT="$REPO/.."
|
||||
ARCH="$(VSCODE_ARCH)"
|
||||
|
||||
# Publish tarball
|
||||
PLATFORM_LINUX="linux-$(VSCODE_ARCH)"
|
||||
[[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
|
||||
[[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
|
||||
BUILDNAME="VSCode-$PLATFORM_LINUX"
|
||||
BUILD="$ROOT/$BUILDNAME"
|
||||
BUILD_VERSION="$(date +%s)"
|
||||
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
|
||||
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
|
||||
PACKAGEJSON="$BUILD/resources/app/package.json"
|
||||
VERSION=$(node -p "require(\"$PACKAGEJSON\").version")
|
||||
|
||||
rm -rf $ROOT/code-*.tar.*
|
||||
(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME)
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
|
||||
|
||||
# Publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" "$(VSCODE_HOCKEYAPP_ID_LINUX64)"
|
||||
|
||||
# Publish DEB
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-deb"
|
||||
PLATFORM_DEB="linux-deb-$ARCH"
|
||||
[[ "$ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
|
||||
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
|
||||
DEB_PATH="$REPO/.build/linux/deb/$DEB_ARCH/deb/$DEB_FILENAME"
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" package "$DEB_FILENAME" "$VERSION" true "$DEB_PATH"
|
||||
|
||||
# Publish RPM
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-build-rpm"
|
||||
PLATFORM_RPM="linux-rpm-$ARCH"
|
||||
[[ "$ARCH" == "ia32" ]] && RPM_ARCH="i386" || 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"
|
||||
|
||||
AZURE_DOCUMENTDB_MASTERKEY="$(AZURE_DOCUMENTDB_MASTERKEY)" \
|
||||
AZURE_STORAGE_ACCESS_KEY_2="$(AZURE_STORAGE_ACCESS_KEY_2)" \
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_RPM" package "$RPM_FILENAME" "$VERSION" true "$RPM_PATH"
|
||||
|
||||
# Publish Snap
|
||||
npm run gulp -- "vscode-linux-$(VSCODE_ARCH)-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"
|
||||
rm -rf $SNAP_TARBALL_PATH
|
||||
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
|
||||
VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)" \
|
||||
VSCODE_HOCKEYAPP_TOKEN="$(VSCODE_HOCKEYAPP_TOKEN)" \
|
||||
./build/azure-pipelines/linux/publish.sh
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
51
build/azure-pipelines/linux/publish.sh
Executable file
51
build/azure-pipelines/linux/publish.sh
Executable file
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
REPO="$(pwd)"
|
||||
ROOT="$REPO/.."
|
||||
|
||||
# Publish tarball
|
||||
PLATFORM_LINUX="linux-$VSCODE_ARCH"
|
||||
[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
|
||||
[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || RPM_ARCH="x86_64"
|
||||
BUILDNAME="VSCode-$PLATFORM_LINUX"
|
||||
BUILD="$ROOT/$BUILDNAME"
|
||||
BUILD_VERSION="$(date +%s)"
|
||||
[ -z "$VSCODE_QUALITY" ] && TARBALL_FILENAME="code-$BUILD_VERSION.tar.gz" || TARBALL_FILENAME="code-$VSCODE_QUALITY-$BUILD_VERSION.tar.gz"
|
||||
TARBALL_PATH="$ROOT/$TARBALL_FILENAME"
|
||||
PACKAGEJSON="$BUILD/resources/app/package.json"
|
||||
VERSION=$(node -p "require(\"$PACKAGEJSON\").version")
|
||||
|
||||
rm -rf $ROOT/code-*.tar.*
|
||||
(cd $ROOT && tar -czf $TARBALL_PATH $BUILDNAME)
|
||||
|
||||
node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_LINUX" archive-unsigned "$TARBALL_FILENAME" "$VERSION" true "$TARBALL_PATH"
|
||||
|
||||
# Publish hockeyapp symbols
|
||||
node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_HOCKEYAPP_TOKEN" "$VSCODE_ARCH" "$VSCODE_HOCKEYAPP_ID_LINUX64"
|
||||
|
||||
# Publish DEB
|
||||
yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb"
|
||||
PLATFORM_DEB="linux-deb-$VSCODE_ARCH"
|
||||
[[ "$VSCODE_ARCH" == "ia32" ]] && DEB_ARCH="i386" || DEB_ARCH="amd64"
|
||||
DEB_FILENAME="$(ls $REPO/.build/linux/deb/$DEB_ARCH/deb/)"
|
||||
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"
|
||||
[[ "$VSCODE_ARCH" == "ia32" ]] && RPM_ARCH="i386" || 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"
|
||||
|
||||
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"
|
||||
|
||||
# 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"
|
||||
rm -rf $SNAP_TARBALL_PATH
|
||||
(cd .build/linux && tar -czf $SNAP_TARBALL_PATH snap)
|
||||
4
build/azure-pipelines/win32/build.ps1
Normal file
4
build/azure-pipelines/win32/build.ps1
Normal file
@@ -0,0 +1,4 @@
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-min" }
|
||||
exec { yarn gulp "vscode-win32-$env:VSCODE_ARCH-inno-updater" }
|
||||
@@ -18,34 +18,47 @@ steps:
|
||||
"machine monacotools.visualstudio.com`npassword $(VSO_PAT)`nmachine github.com`nlogin vscode`npassword $(VSCODE_MIXIN_PASSWORD)" | Out-File "$env:USERPROFILE\_netrc" -Encoding ASCII
|
||||
$env:npm_config_arch="$(VSCODE_ARCH)"
|
||||
$env:CHILD_CONCURRENCY="1"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
|
||||
exec { git config user.email "vscode@microsoft.com" }
|
||||
exec { git config user.name "VSCode" }
|
||||
exec { git remote add distro "https://github.com/$(VSCODE_MIXIN_REPO).git" }
|
||||
exec { git fetch distro }
|
||||
exec { git merge $(node -p "require('./package.json').distro") }
|
||||
|
||||
exec { yarn }
|
||||
exec { npm run gulp -- mixin }
|
||||
exec { npm run gulp -- hygiene }
|
||||
exec { npm run monaco-compile-check }
|
||||
exec { yarn gulp mixin }
|
||||
exec { yarn gulp hygiene }
|
||||
exec { yarn monaco-compile-check }
|
||||
exec { node build/azure-pipelines/common/installDistro.js }
|
||||
exec { node build/lib/builtInExtensions.js }
|
||||
displayName: Prepare build
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
$env:VSCODE_MIXIN_PASSWORD="$(VSCODE_MIXIN_PASSWORD)"
|
||||
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-min" }
|
||||
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-inno-updater" }
|
||||
name: build
|
||||
.\build\azure-pipelines\win32\build.ps1
|
||||
displayName: Build
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp -- "electron-$(VSCODE_ARCH)" }
|
||||
exec { yarn gulp "electron-$(VSCODE_ARCH)" }
|
||||
exec { .\scripts\test.bat --build --tfs "Unit Tests" }
|
||||
# yarn smoketest -- --build "$(agent.builddirectory)\VSCode-win32-$(VSCODE_ARCH)"
|
||||
name: test
|
||||
displayName: Run unit tests
|
||||
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { yarn gulp "electron-$(VSCODE_ARCH)" }
|
||||
exec { .\scripts\test-integration.bat --build --tfs "Integration Tests" }
|
||||
displayName: Run integration tests
|
||||
|
||||
- task: SFP.build-tasks.custom-build-task-1.EsrpCodeSigning@1
|
||||
inputs:
|
||||
ConnectedServiceName: 'ESRP CodeSign'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH)'
|
||||
FolderPath: '$(agent.builddirectory)/VSCode-win32-$(VSCODE_ARCH),$(agent.builddirectory)/vscode-reh-win32-$(VSCODE_ARCH)'
|
||||
Pattern: '*.dll,*.exe,*.node'
|
||||
signConfigType: inlineSignParams
|
||||
inlineOperation: |
|
||||
@@ -119,31 +132,11 @@ steps:
|
||||
- powershell: |
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
exec { npm run gulp -- "vscode-win32-$(VSCODE_ARCH)-archive" "vscode-win32-$(VSCODE_ARCH)-system-setup" "vscode-win32-$(VSCODE_ARCH)-user-setup" --sign }
|
||||
|
||||
$Repo = "$(pwd)"
|
||||
$Root = "$Repo\.."
|
||||
$SystemExe = "$Repo\.build\win32-$(VSCODE_ARCH)\system-setup\VSCodeSetup.exe"
|
||||
$UserExe = "$Repo\.build\win32-$(VSCODE_ARCH)\user-setup\VSCodeSetup.exe"
|
||||
$Zip = "$Repo\.build\win32-$(VSCODE_ARCH)\archive\VSCode-win32-$(VSCODE_ARCH).zip"
|
||||
$Build = "$Root\VSCode-win32-$(VSCODE_ARCH)"
|
||||
|
||||
# get version
|
||||
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
$Quality = "$env:VSCODE_QUALITY"
|
||||
$env:AZURE_STORAGE_ACCESS_KEY_2 = "$(AZURE_STORAGE_ACCESS_KEY_2)"
|
||||
$env:AZURE_DOCUMENTDB_MASTERKEY = "$(AZURE_DOCUMENTDB_MASTERKEY)"
|
||||
|
||||
$assetPlatform = if ("$(VSCODE_ARCH)" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-archive" archive "VSCode-win32-$(VSCODE_ARCH)-$Version.zip" $Version true $Zip }
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform" setup "VSCodeSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $SystemExe }
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$global:assetPlatform-user" setup "VSCodeUserSetup-$(VSCODE_ARCH)-$Version.exe" $Version true $UserExe }
|
||||
|
||||
# publish hockeyapp symbols
|
||||
$hockeyAppId = if ("$(VSCODE_ARCH)" -eq "ia32") { "$(VSCODE_HOCKEYAPP_ID_WIN32)" } else { "$(VSCODE_HOCKEYAPP_ID_WIN64)" }
|
||||
exec { node build/azure-pipelines/common/symbols.js "$(VSCODE_MIXIN_PASSWORD)" "$(VSCODE_HOCKEYAPP_TOKEN)" "$(VSCODE_ARCH)" $hockeyAppId }
|
||||
$env:VSCODE_HOCKEYAPP_TOKEN = "$(VSCODE_HOCKEYAPP_TOKEN)"
|
||||
.\build\azure-pipelines\win32\publish.ps1
|
||||
displayName: Publish
|
||||
|
||||
- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0
|
||||
displayName: 'Component Detection'
|
||||
|
||||
28
build/azure-pipelines/win32/publish.ps1
Normal file
28
build/azure-pipelines/win32/publish.ps1
Normal file
@@ -0,0 +1,28 @@
|
||||
. build/azure-pipelines/win32/exec.ps1
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$Arch = "$env:VSCODE_ARCH"
|
||||
|
||||
exec { yarn gulp "vscode-win32-$Arch-archive" "vscode-win32-$Arch-system-setup" "vscode-win32-$Arch-user-setup" --sign }
|
||||
|
||||
$Repo = "$(pwd)"
|
||||
$Root = "$Repo\.."
|
||||
$SystemExe = "$Repo\.build\win32-$Arch\system-setup\VSCodeSetup.exe"
|
||||
$UserExe = "$Repo\.build\win32-$Arch\user-setup\VSCodeSetup.exe"
|
||||
$Zip = "$Repo\.build\win32-$Arch\archive\VSCode-win32-$Arch.zip"
|
||||
$Build = "$Root\VSCode-win32-$Arch"
|
||||
|
||||
# get version
|
||||
$PackageJson = Get-Content -Raw -Path "$Build\resources\app\package.json" | ConvertFrom-Json
|
||||
$Version = $PackageJson.version
|
||||
$Quality = "$env:VSCODE_QUALITY"
|
||||
|
||||
$AssetPlatform = if ("$Arch" -eq "ia32") { "win32" } else { "win32-x64" }
|
||||
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-archive" archive "VSCode-win32-$Arch-$Version.zip" $Version true $Zip }
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform" setup "VSCodeSetup-$Arch-$Version.exe" $Version true $SystemExe }
|
||||
exec { node build/azure-pipelines/common/publish.js $Quality "$AssetPlatform-user" setup "VSCodeUserSetup-$Arch-$Version.exe" $Version true $UserExe }
|
||||
|
||||
# publish hockeyapp symbols
|
||||
$hockeyAppId = if ("$Arch" -eq "ia32") { "$env:VSCODE_HOCKEYAPP_ID_WIN32" } else { "$env:VSCODE_HOCKEYAPP_ID_WIN64" }
|
||||
exec { node build/azure-pipelines/common/symbols.js "$env:VSCODE_MIXIN_PASSWORD" "$env:VSCODE_HOCKEYAPP_TOKEN" "$Arch" $hockeyAppId }
|
||||
@@ -75,9 +75,10 @@ const vscodeResources = [
|
||||
'out-build/bootstrap-window.js',
|
||||
'out-build/paths.js',
|
||||
'out-build/vs/**/*.{svg,png,cur,html}',
|
||||
'!out-build/vs/code/browser/**/*.html',
|
||||
'out-build/vs/base/common/performance.js',
|
||||
'out-build/vs/base/node/languagePacks.js',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh}',
|
||||
'out-build/vs/base/node/{stdForkStart.js,terminateProcess.sh,cpuUsage.sh,ps.sh}',
|
||||
'out-build/vs/base/browser/ui/octiconLabel/octicons/**',
|
||||
'out-build/vs/workbench/browser/media/*-theme.css',
|
||||
'out-build/vs/workbench/contrib/debug/**/*.json',
|
||||
@@ -431,6 +432,7 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op
|
||||
.pipe(replace('@@VERSION@@', version))
|
||||
.pipe(replace('@@COMMIT@@', commit))
|
||||
.pipe(replace('@@APPNAME@@', product.applicationName))
|
||||
.pipe(replace('@@QUALITY@@', quality))
|
||||
.pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; })));
|
||||
|
||||
result = es.merge(result, gulp.src('resources/win32/VisualElementsManifest.xml', { base: 'resources/win32' })
|
||||
|
||||
@@ -237,6 +237,7 @@ exports.fromMarketplace = fromMarketplace;
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-colorize-tests',
|
||||
'vscode-test-resolver',
|
||||
'ms-vscode.node-debug',
|
||||
'ms-vscode.node-debug2',
|
||||
// {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -283,6 +283,7 @@ interface IPackageExtensionsOptions {
|
||||
const excludedExtensions = [
|
||||
'vscode-api-tests',
|
||||
'vscode-colorize-tests',
|
||||
'vscode-test-resolver',
|
||||
'ms-vscode.node-debug',
|
||||
'ms-vscode.node-debug2',
|
||||
// {{SQL CARBON EDIT}}
|
||||
|
||||
@@ -111,11 +111,11 @@
|
||||
"git": {
|
||||
"name": "vscode-octicons-font",
|
||||
"repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font",
|
||||
"commitHash": "5095860bb929919670646e2dfa0ee47d9b93bcb9"
|
||||
"commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42"
|
||||
}
|
||||
},
|
||||
"license": "MIT",
|
||||
"version": "1.0.0"
|
||||
"version": "1.1.0"
|
||||
},
|
||||
{
|
||||
"component": {
|
||||
|
||||
@@ -1031,7 +1031,7 @@
|
||||
],
|
||||
"markdownDescription": "%config.path%",
|
||||
"default": null,
|
||||
"scope": "application"
|
||||
"scope": "machine"
|
||||
},
|
||||
"git.autoRepositoryDetection": {
|
||||
"type": [
|
||||
|
||||
@@ -381,7 +381,14 @@ export class MarkdownPreview extends Disposable {
|
||||
clearTimeout(this.throttleTimer);
|
||||
this.throttleTimer = undefined;
|
||||
|
||||
const document = await vscode.workspace.openTextDocument(resource);
|
||||
let document: vscode.TextDocument;
|
||||
try {
|
||||
document = await vscode.workspace.openTextDocument(resource);
|
||||
} catch {
|
||||
await this.showFileNotFoundError();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.forceUpdate && this.currentVersion && this.currentVersion.resource.fsPath === resource.fsPath && this.currentVersion.version === document.version) {
|
||||
if (this.line) {
|
||||
this.updateForView(resource, this.line);
|
||||
@@ -391,12 +398,9 @@ export class MarkdownPreview extends Disposable {
|
||||
this.forceUpdate = false;
|
||||
|
||||
this.currentVersion = { resource, version: document.version };
|
||||
const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state);
|
||||
if (this._resource === resource) {
|
||||
this.editor.title = MarkdownPreview.getPreviewTitle(this._resource, this._locked);
|
||||
this.editor.iconPath = this.iconPath;
|
||||
this.editor.webview.options = MarkdownPreview.getWebviewOptions(resource, this._contributionProvider.contributions);
|
||||
this.editor.webview.html = content;
|
||||
const content = await this._contentProvider.provideTextDocumentContent(document, this._previewConfigurations, this.line, this.state);
|
||||
this.setContent(content);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,7 +460,22 @@ export class MarkdownPreview extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
vscode.workspace.openTextDocument(this._resource).then(vscode.window.showTextDocument);
|
||||
vscode.workspace.openTextDocument(this._resource)
|
||||
.then(vscode.window.showTextDocument)
|
||||
.then(undefined, () => {
|
||||
vscode.window.showErrorMessage(localize('preview.clickOpenFailed', 'Could not open {0}', this._resource.toString()));
|
||||
});
|
||||
}
|
||||
|
||||
private async showFileNotFoundError() {
|
||||
this.setContent(this._contentProvider.provideFileNotFoundContent(this._resource));
|
||||
}
|
||||
|
||||
private setContent(html: string): void {
|
||||
this.editor.title = MarkdownPreview.getPreviewTitle(this._resource, this._locked);
|
||||
this.editor.iconPath = this.iconPath;
|
||||
this.editor.webview.options = MarkdownPreview.getWebviewOptions(this._resource, this._contributionProvider.contributions);
|
||||
this.editor.webview.html = html;
|
||||
}
|
||||
|
||||
private async onDidClickPreviewLink(path: string, fragment: string | undefined) {
|
||||
|
||||
@@ -90,6 +90,19 @@ export class MarkdownContentProvider {
|
||||
</html>`;
|
||||
}
|
||||
|
||||
public provideFileNotFoundContent(
|
||||
resource: vscode.Uri,
|
||||
): string {
|
||||
const resourcePath = path.basename(resource.fsPath);
|
||||
const body = localize('preview.notFound', '{0} cannot be found', resourcePath);
|
||||
return `<!DOCTYPE html>
|
||||
<html>
|
||||
<body class="vscode-body">
|
||||
${body}
|
||||
</body>
|
||||
</html>`;
|
||||
}
|
||||
|
||||
private extensionResourcePath(mediaFile: string): string {
|
||||
return vscode.Uri.file(this.context.asAbsolutePath(path.join('media', mediaFile)))
|
||||
.with({ scheme: 'vscode-resource' })
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
"version": "0.0.1",
|
||||
"description": "Dependencies shared by all extensions",
|
||||
"dependencies": {
|
||||
"typescript": "3.4.3-insiders.20190408"
|
||||
"typescript": "3.4.3"
|
||||
},
|
||||
"scripts": {
|
||||
"postinstall": "node ./postinstall"
|
||||
|
||||
@@ -68,7 +68,12 @@
|
||||
},
|
||||
{
|
||||
"name": "Control flow keywords",
|
||||
"scope": "keyword.control",
|
||||
"scope": [
|
||||
"keyword.control",
|
||||
"keyword.operator.new.cpp",
|
||||
"keyword.operator.delete.cpp",
|
||||
"keyword.other.using"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#C586C0"
|
||||
}
|
||||
|
||||
@@ -65,7 +65,12 @@
|
||||
},
|
||||
{
|
||||
"name": "Control flow keywords",
|
||||
"scope": "keyword.control",
|
||||
"scope": [
|
||||
"keyword.control",
|
||||
"keyword.operator.new.cpp",
|
||||
"keyword.operator.delete.cpp",
|
||||
"keyword.other.using"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#C586C0"
|
||||
}
|
||||
|
||||
@@ -68,7 +68,12 @@
|
||||
},
|
||||
{
|
||||
"name": "Control flow keywords",
|
||||
"scope": "keyword.control",
|
||||
"scope": [
|
||||
"keyword.control",
|
||||
"keyword.operator.new.cpp",
|
||||
"keyword.operator.delete.cpp",
|
||||
"keyword.other.using"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#AF00DB"
|
||||
}
|
||||
|
||||
@@ -113,7 +113,10 @@
|
||||
"name": "Keywords",
|
||||
"scope": [
|
||||
"keyword",
|
||||
"keyword.control"
|
||||
"keyword.control",
|
||||
"keyword.operator.new.cpp",
|
||||
"keyword.operator.delete.cpp",
|
||||
"keyword.other.using"
|
||||
],
|
||||
"settings": {
|
||||
"foreground": "#98676a"
|
||||
|
||||
@@ -255,7 +255,12 @@
|
||||
},
|
||||
{
|
||||
"name": "Keyword Control",
|
||||
"scope": "keyword.control",
|
||||
"scope": [
|
||||
"keyword.control",
|
||||
"keyword.operator.new.cpp",
|
||||
"keyword.operator.delete.cpp",
|
||||
"keyword.other.using"
|
||||
],
|
||||
"settings": {
|
||||
"fontStyle": "",
|
||||
"foreground": "#9872A2"
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as Proto from '../protocol';
|
||||
import { ITypeScriptServiceClient } from '../typescriptService';
|
||||
import API from '../utils/api';
|
||||
import { VersionDependentRegistration } from '../utils/dependentRegistration';
|
||||
import * as typeConverters from '../utils/typeConverters';
|
||||
|
||||
class SmartSelection implements vscode.SelectionRangeProvider {
|
||||
public static readonly minVersion = API.v350;
|
||||
|
||||
public constructor(
|
||||
private readonly client: ITypeScriptServiceClient
|
||||
) { }
|
||||
|
||||
public async provideSelectionRanges(
|
||||
document: vscode.TextDocument,
|
||||
positions: vscode.Position[],
|
||||
token: vscode.CancellationToken,
|
||||
): Promise<vscode.SelectionRange[] | undefined> {
|
||||
const file = this.client.toOpenedFilePath(document);
|
||||
if (!file) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const args: Proto.FileRequestArgs & { locations: Proto.Location[] } = {
|
||||
file,
|
||||
locations: positions.map(typeConverters.Position.toLocation)
|
||||
};
|
||||
const response = await this.client.execute('selectionRange', args, token);
|
||||
if (response.type !== 'response' || !response.body) {
|
||||
return undefined;
|
||||
}
|
||||
return response.body.map(SmartSelection.convertSelectionRange);
|
||||
}
|
||||
|
||||
private static convertSelectionRange(
|
||||
selectionRange: Proto.SelectionRange
|
||||
): vscode.SelectionRange {
|
||||
return new vscode.SelectionRange(
|
||||
typeConverters.Range.fromTextSpan(selectionRange.textSpan),
|
||||
selectionRange.parent ? SmartSelection.convertSelectionRange(selectionRange.parent) : undefined,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export function register(
|
||||
selector: vscode.DocumentSelector,
|
||||
client: ITypeScriptServiceClient,
|
||||
) {
|
||||
return new VersionDependentRegistration(client, SmartSelection.minVersion, () =>
|
||||
vscode.languages.registerSelectionRangeProvider(selector, new SmartSelection(client)));
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* 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 'mocha';
|
||||
import * as vscode from 'vscode';
|
||||
import { CURSOR, withRandomFileEditor } from './testUtils';
|
||||
|
||||
const onDocumentChange = (doc: vscode.TextDocument): Promise<vscode.TextDocument> => {
|
||||
return new Promise<vscode.TextDocument>(resolve => {
|
||||
const sub = vscode.workspace.onDidChangeTextDocument(e => {
|
||||
if (e.document !== doc) {
|
||||
return;
|
||||
}
|
||||
sub.dispose();
|
||||
resolve(e.document);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
const type = async (document: vscode.TextDocument, text: string): Promise<vscode.TextDocument> => {
|
||||
const onChange = onDocumentChange(document);
|
||||
await vscode.commands.executeCommand('type', { text });
|
||||
await onChange;
|
||||
return document;
|
||||
};
|
||||
|
||||
suite('OnEnter', () => {
|
||||
test('should indent after if block with braces', () => {
|
||||
return withRandomFileEditor(`if (true) {${CURSOR}`, 'js', async (_editor, document) => {
|
||||
await type(document, '\nx');
|
||||
assert.strictEqual(document.getText(), `if (true) {\n x`);
|
||||
});
|
||||
});
|
||||
|
||||
test('should indent within empty object literal', () => {
|
||||
return withRandomFileEditor(`({${CURSOR}})`, 'js', async (_editor, document) => {
|
||||
await type(document, '\nx');
|
||||
assert.strictEqual(document.getText(), `({\n x\n})`);
|
||||
});
|
||||
});
|
||||
|
||||
test('should indent after simple jsx tag with attributes', () => {
|
||||
return withRandomFileEditor(`const a = <div onclick={bla}>${CURSOR}`, 'jsx', async (_editor, document) => {
|
||||
await type(document, '\nx');
|
||||
assert.strictEqual(document.getText(), `const a = <div onclick={bla}>\n x`);
|
||||
});
|
||||
});
|
||||
|
||||
test('should indent after simple jsx tag with attributes', () => {
|
||||
return withRandomFileEditor(`const a = <div onclick={bla}>${CURSOR}`, 'jsx', async (_editor, document) => {
|
||||
await type(document, '\nx');
|
||||
assert.strictEqual(document.getText(), `const a = <div onclick={bla}>\n x`);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,68 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import * as fs from 'fs';
|
||||
import * as os from 'os';
|
||||
import { join } from 'path';
|
||||
|
||||
function rndName() {
|
||||
return Math.random().toString(36).replace(/[^a-z]+/g, '').substr(0, 10);
|
||||
}
|
||||
|
||||
export function createRandomFile(contents = '', fileExtension = 'txt'): Thenable<vscode.Uri> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const tmpFile = join(os.tmpdir(), rndName() + '.' + fileExtension);
|
||||
fs.writeFile(tmpFile, contents, (error) => {
|
||||
if (error) {
|
||||
return reject(error);
|
||||
}
|
||||
|
||||
resolve(vscode.Uri.file(tmpFile));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function deleteFile(file: vscode.Uri): Thenable<boolean> {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.unlink(file.fsPath, (err) => {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export const CURSOR = '$$CURSOR$$';
|
||||
|
||||
export function withRandomFileEditor(
|
||||
contents: string,
|
||||
fileExtension: string,
|
||||
run: (editor: vscode.TextEditor, doc: vscode.TextDocument) => Thenable<void>
|
||||
): Thenable<boolean> {
|
||||
const cursorIndex = contents.indexOf(CURSOR);
|
||||
return createRandomFile(contents.replace(CURSOR, ''), fileExtension).then(file => {
|
||||
return vscode.workspace.openTextDocument(file).then(doc => {
|
||||
return vscode.window.showTextDocument(doc).then((editor) => {
|
||||
if (cursorIndex >= 0) {
|
||||
const pos = doc.positionAt(cursorIndex);
|
||||
editor.selection = new vscode.Selection(pos, pos);
|
||||
}
|
||||
return run(editor, doc).then(_ => {
|
||||
if (doc.isDirty) {
|
||||
return doc.save().then(() => {
|
||||
return deleteFile(file);
|
||||
});
|
||||
} else {
|
||||
return deleteFile(file);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
# yarn lockfile v1
|
||||
|
||||
|
||||
typescript@3.4.3-insiders.20190408:
|
||||
version "3.4.3-insiders.20190408"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3-insiders.20190408.tgz#18d98336c693a13dc8b2d5f39b70268c018c650b"
|
||||
integrity sha512-5SI6EA+2u0ea/Uy0qCEczh8vBR0ByVaCFCyU0RdROROw8V5O4OIQHMFcnIdyg+nnfRGYp39PxvllGMDpsTFOOQ==
|
||||
typescript@3.4.3:
|
||||
version "3.4.3"
|
||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.3.tgz#0eb320e4ace9b10eadf5bc6103286b0f8b7c224f"
|
||||
integrity sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"vscode-ripgrep": "^1.2.5",
|
||||
"vscode-sqlite3": "4.0.7",
|
||||
"vscode-textmate": "^4.0.1",
|
||||
"vscode-xterm": "3.13.0-beta2",
|
||||
"vscode-xterm": "3.13.0-beta3",
|
||||
"yauzl": "^2.9.1",
|
||||
"yazl": "^2.4.3",
|
||||
"zone.js": "^0.8.4"
|
||||
@@ -119,6 +119,7 @@
|
||||
"gulp-eslint": "^5.0.0",
|
||||
"gulp-filter": "^5.1.0",
|
||||
"gulp-flatmap": "^1.0.2",
|
||||
"gulp-gunzip": "^1.0.0",
|
||||
"gulp-json-editor": "^2.5.0",
|
||||
"gulp-plumber": "^1.2.0",
|
||||
"gulp-remote-src": "^0.4.4",
|
||||
@@ -128,6 +129,7 @@
|
||||
"gulp-tsb": "2.0.7",
|
||||
"gulp-tslint": "^8.1.3",
|
||||
"gulp-uglify": "^3.0.0",
|
||||
"gulp-untar": "^0.0.7",
|
||||
"gulp-vinyl-zip": "^2.1.2",
|
||||
"husky": "^0.13.1",
|
||||
"innosetup-compiler": "^5.5.60",
|
||||
@@ -177,8 +179,8 @@
|
||||
"url": "https://github.com/Microsoft/azuredatastudio/issues"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"vscode-windows-registry": "1.0.1",
|
||||
"vscode-windows-ca-certs": "0.1.0",
|
||||
"vscode-windows-registry": "1.0.1",
|
||||
"windows-foreground-love": "0.1.0",
|
||||
"windows-mutex": "0.2.1",
|
||||
"windows-process-tree": "0.2.3"
|
||||
@@ -189,4 +191,4 @@
|
||||
"natives": "1.1.6",
|
||||
"@types/node": "10.12.12"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,15 @@
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
|
||||
# test that VSCode wasn't installed inside WSL
|
||||
if grep -qi Microsoft /proc/version; then
|
||||
echo "To use VS Code with the Windows Subsystem for Linux, please install VS Code in Windows and uninstall the Linux version in WSL. You can then use the '@@PRODNAME@@' command in a WSL terminal just as you would in a normal command prompt." 1>&2
|
||||
read -e -p "Do you want to continue anyways ? [y/N] " YN
|
||||
|
||||
[[ $YN == "n" || $YN == "N" || $YN == "" ]] && exit 1
|
||||
fi
|
||||
|
||||
|
||||
# If root, ensure that --user-data-dir or --file-write is specified
|
||||
if [ "$(id -u)" = "0" ]; then
|
||||
for i in $@
|
||||
|
||||
@@ -2,28 +2,31 @@
|
||||
#
|
||||
# Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
# Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
COMMIT="@@COMMIT@@"
|
||||
APP_NAME="@@APPNAME@@"
|
||||
QUALITY="@@QUALITY@@"
|
||||
|
||||
NAME="@@NAME@@"
|
||||
VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")"
|
||||
ELECTRON="$VSCODE_PATH/$NAME.exe"
|
||||
if grep -q Microsoft /proc/version; then
|
||||
if [ -x /bin/wslpath ]; then
|
||||
# On recent WSL builds, we just need to set WSLENV so that
|
||||
# ELECTRON_RUN_AS_NODE is visible to the win32 process
|
||||
export WSLENV=ELECTRON_RUN_AS_NODE/w:$WSLENV
|
||||
CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||
else
|
||||
# If running under older WSL, don't pass cli.js to Electron as
|
||||
# environment vars cannot be transferred from WSL to Windows
|
||||
# See: https://github.com/Microsoft/BashOnWindows/issues/1363
|
||||
# https://github.com/Microsoft/BashOnWindows/issues/1494
|
||||
"$ELECTRON" "$@"
|
||||
set -e
|
||||
|
||||
if grep -qi Microsoft /proc/version; then
|
||||
# in a wsl shell
|
||||
WIN_CODE_CMD=$(wslpath -w "$(dirname "$(realpath "$0")")/$APP_NAME.cmd")
|
||||
|
||||
WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||
WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CMD" --locate-extension $WSL_EXT_ID)
|
||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC, get linux path for
|
||||
WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh
|
||||
$WSL_CODE $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@"
|
||||
exit $?
|
||||
fi
|
||||
elif [ "$(expr substr $(uname -s) 1 9)" == "CYGWIN_NT" ]; then
|
||||
fi
|
||||
|
||||
if [ -x "$(command -v cygpath)" ]; then
|
||||
CLI=$(cygpath -m "$VSCODE_PATH/resources/app/out/cli.js")
|
||||
else
|
||||
CLI="$VSCODE_PATH/resources/app/out/cli.js"
|
||||
fi
|
||||
ELECTRON="$VSCODE_PATH/$NAME.exe"
|
||||
ELECTRON_RUN_AS_NODE=1 "$ELECTRON" "$CLI" "$@"
|
||||
exit $?
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -e
|
||||
|
||||
if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
realpath() { [[ $1 = /* ]] && echo "$1" || echo "$PWD/${1#./}"; }
|
||||
ROOT=$(dirname "$(dirname "$(realpath "$0")")")
|
||||
@@ -9,6 +11,9 @@ if [[ "$OSTYPE" == "darwin"* ]]; then
|
||||
export ELECTRON_ENABLE_LOGGING=1
|
||||
else
|
||||
ROOT=$(dirname "$(dirname "$(readlink -f $0)")")
|
||||
if grep -qi Microsoft /proc/version; then
|
||||
IN_WSL=true
|
||||
fi
|
||||
fi
|
||||
|
||||
function code() {
|
||||
@@ -50,4 +55,23 @@ function code() {
|
||||
exec "$CODE" . "$@"
|
||||
}
|
||||
|
||||
code "$@"
|
||||
function code-wsl()
|
||||
{
|
||||
# in a wsl shell
|
||||
local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat")
|
||||
|
||||
local WSL_EXT_ID="ms-vscode.remote-wsl"
|
||||
local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID)
|
||||
if ! [ -z "$WSL_EXT_WLOC" ]; then
|
||||
# replace \r\n with \n in WSL_EXT_WLOC
|
||||
local WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode-dev.sh
|
||||
$WSL_CODE "$ROOT" "$@"
|
||||
exit $?
|
||||
fi
|
||||
}
|
||||
|
||||
if [ -z ${IN_WSL+x} ]; then
|
||||
code "$@"
|
||||
else
|
||||
code-wsl "$@"
|
||||
fi
|
||||
4
src/bootstrap-fork.js
vendored
4
src/bootstrap-fork.js
vendored
@@ -11,6 +11,10 @@ const bootstrap = require('./bootstrap');
|
||||
// Enable ASAR in our forked processes
|
||||
bootstrap.enableASARSupport();
|
||||
|
||||
if (process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']) {
|
||||
bootstrap.injectNodeModuleLookupPath(process.env['VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH']);
|
||||
}
|
||||
|
||||
// Configure: pipe logging to parent process
|
||||
if (!!process.send && process.env.PIPE_LOGGING === 'true') {
|
||||
pipeLoggingToParent();
|
||||
|
||||
32
src/bootstrap.js
vendored
32
src/bootstrap.js
vendored
@@ -20,6 +20,38 @@ process.on('SIGPIPE', () => {
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Add support for redirecting the loading of node modules
|
||||
exports.injectNodeModuleLookupPath = function (injectPath) {
|
||||
if (!injectPath) {
|
||||
throw new Error('Missing injectPath');
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
const Module = require('module');
|
||||
const path = require('path');
|
||||
|
||||
const nodeModulesPath = path.join(__dirname, '../node_modules');
|
||||
|
||||
// @ts-ignore
|
||||
const originalResolveLookupPaths = Module._resolveLookupPaths;
|
||||
|
||||
// @ts-ignore
|
||||
Module._resolveLookupPaths = function (moduleName, parent, newReturn) {
|
||||
const result = originalResolveLookupPaths(moduleName, parent, newReturn);
|
||||
|
||||
const paths = newReturn ? result : result[1];
|
||||
for (let i = 0, len = paths.length; i < len; i++) {
|
||||
if (paths[i] === nodeModulesPath) {
|
||||
paths.splice(i, 0, injectPath);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
};
|
||||
};
|
||||
//#endregion
|
||||
|
||||
//#region Add support for using node_modules.asar
|
||||
/**
|
||||
* @param {string=} nodeModulesPath
|
||||
|
||||
@@ -41,6 +41,7 @@ import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { ExtHostConfiguration, ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
|
||||
export interface ISqlExtensionApiFactory {
|
||||
vsCodeFactory(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -58,9 +59,11 @@ export function createApiFactory(
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extensionService: ExtHostExtensionService,
|
||||
logService: ExtHostLogService,
|
||||
extHostStorage: ExtHostStorage
|
||||
extHostStorage: ExtHostStorage,
|
||||
schemeTransformer: ISchemeTransformer | null,
|
||||
outputChannelName: string
|
||||
): ISqlExtensionApiFactory {
|
||||
let vsCodeFactory = extHostApi.createApiFactory(initData, rpcProtocol, extHostWorkspace, extHostConfiguration, extensionService, logService, extHostStorage);
|
||||
let vsCodeFactory = extHostApi.createApiFactory(initData, rpcProtocol, extHostWorkspace, extHostConfiguration, extensionService, logService, extHostStorage, schemeTransformer, outputChannelName);
|
||||
|
||||
// Addressable instances
|
||||
const extHostAccountManagement = rpcProtocol.set(SqlExtHostContext.ExtHostAccountManagement, new ExtHostAccountManagement(rpcProtocol));
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import { ITelemetryService, ITelemetryInfo, ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
||||
const fs = require('fs');
|
||||
|
||||
/**
|
||||
* Write telemetry into a file for test purposes
|
||||
*/
|
||||
export class FileTelemetryService implements ITelemetryService {
|
||||
_serviceBrand: undefined;
|
||||
private _isFirst = true;
|
||||
|
||||
constructor(private _outputFile: string) {
|
||||
}
|
||||
|
||||
publicLog(eventName: string, data?: ITelemetryData) {
|
||||
let telemetryData = JSON.stringify(Object.assign({ eventName: eventName, data: data }));
|
||||
if (this._outputFile) {
|
||||
if (this._isFirst) {
|
||||
fs.open(this._outputFile, fs.O_WRONLY | fs.O_CREAT, (err, fr) => {
|
||||
fs.writeFileSync(this._outputFile, telemetryData + '\n');
|
||||
this._isFirst = false;
|
||||
});
|
||||
} else {
|
||||
fs.appendFileSync(this._outputFile, telemetryData + '\n');
|
||||
}
|
||||
}
|
||||
return Promise.resolve<void>(null);
|
||||
}
|
||||
isOptedIn: true;
|
||||
getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||
return Promise.resolve({
|
||||
instanceId: 'someValue.instanceId',
|
||||
sessionId: 'someValue.sessionId',
|
||||
machineId: 'someValue.machineId'
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/t
|
||||
// Test stubs for commonly used objects
|
||||
|
||||
export class TelemetryServiceStub implements ITelemetryService {
|
||||
setEnabled(value: boolean): void {
|
||||
// no op;
|
||||
}
|
||||
|
||||
_serviceBrand: any;
|
||||
|
||||
@@ -23,4 +26,4 @@ export class TelemetryServiceStub implements ITelemetryService {
|
||||
}
|
||||
|
||||
isOptedIn: boolean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,18 +1,16 @@
|
||||
{
|
||||
"extends": "./tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"noEmit": true,
|
||||
"types": [],
|
||||
"paths": {},
|
||||
"module": "amd",
|
||||
"moduleResolution": "classic",
|
||||
"noImplicitAny": false,
|
||||
"removeComments": false,
|
||||
"preserveConstEnums": true,
|
||||
"target": "es5",
|
||||
"sourceMap": false,
|
||||
"experimentalDecorators": true,
|
||||
"declaration": true,
|
||||
"noImplicitReturns": true,
|
||||
"baseUrl": ".",
|
||||
"types": []
|
||||
},
|
||||
"include": [
|
||||
"typings/require.d.ts",
|
||||
|
||||
@@ -68,7 +68,7 @@ export const DataTransfers = {
|
||||
FILES: 'Files',
|
||||
|
||||
/**
|
||||
* Typicaly transfer type for copy/paste transfers.
|
||||
* Typically transfer type for copy/paste transfers.
|
||||
*/
|
||||
TEXT: 'text/plain'
|
||||
};
|
||||
|
||||
@@ -467,28 +467,6 @@ export function getComputedStyle(el: HTMLElement): CSSStyleDeclaration {
|
||||
return document.defaultView!.getComputedStyle(el, null);
|
||||
}
|
||||
|
||||
// Adapted from WinJS
|
||||
// Converts a CSS positioning string for the specified element to pixels.
|
||||
const convertToPixels: (element: HTMLElement, value: string) => number = (function () {
|
||||
return function (element: HTMLElement, value: string): number {
|
||||
return parseFloat(value) || 0;
|
||||
};
|
||||
})();
|
||||
|
||||
function getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number {
|
||||
let computedStyle: CSSStyleDeclaration = getComputedStyle(element);
|
||||
let value = '0';
|
||||
if (computedStyle) {
|
||||
if (computedStyle.getPropertyValue) {
|
||||
value = computedStyle.getPropertyValue(cssPropertyName);
|
||||
} else {
|
||||
// IE8
|
||||
value = (<any>computedStyle).getAttribute(jsPropertyName);
|
||||
}
|
||||
}
|
||||
return convertToPixels(element, value);
|
||||
}
|
||||
|
||||
export function getClientArea(element: HTMLElement): Dimension {
|
||||
|
||||
// Try with DOM clientWidth / clientHeight
|
||||
@@ -514,48 +492,66 @@ export function getClientArea(element: HTMLElement): Dimension {
|
||||
throw new Error('Unable to figure out browser width and height');
|
||||
}
|
||||
|
||||
const sizeUtils = {
|
||||
class SizeUtils {
|
||||
// Adapted from WinJS
|
||||
// Converts a CSS positioning string for the specified element to pixels.
|
||||
private static convertToPixels(element: HTMLElement, value: string): number {
|
||||
return parseFloat(value) || 0;
|
||||
}
|
||||
|
||||
getBorderLeftWidth: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'border-left-width', 'borderLeftWidth');
|
||||
},
|
||||
getBorderRightWidth: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'border-right-width', 'borderRightWidth');
|
||||
},
|
||||
getBorderTopWidth: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'border-top-width', 'borderTopWidth');
|
||||
},
|
||||
getBorderBottomWidth: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'border-bottom-width', 'borderBottomWidth');
|
||||
},
|
||||
private static getDimension(element: HTMLElement, cssPropertyName: string, jsPropertyName: string): number {
|
||||
let computedStyle: CSSStyleDeclaration = getComputedStyle(element);
|
||||
let value = '0';
|
||||
if (computedStyle) {
|
||||
if (computedStyle.getPropertyValue) {
|
||||
value = computedStyle.getPropertyValue(cssPropertyName);
|
||||
} else {
|
||||
// IE8
|
||||
value = (<any>computedStyle).getAttribute(jsPropertyName);
|
||||
}
|
||||
}
|
||||
return SizeUtils.convertToPixels(element, value);
|
||||
}
|
||||
|
||||
getPaddingLeft: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'padding-left', 'paddingLeft');
|
||||
},
|
||||
getPaddingRight: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'padding-right', 'paddingRight');
|
||||
},
|
||||
getPaddingTop: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'padding-top', 'paddingTop');
|
||||
},
|
||||
getPaddingBottom: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'padding-bottom', 'paddingBottom');
|
||||
},
|
||||
static getBorderLeftWidth(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'border-left-width', 'borderLeftWidth');
|
||||
}
|
||||
static getBorderRightWidth(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'border-right-width', 'borderRightWidth');
|
||||
}
|
||||
static getBorderTopWidth(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'border-top-width', 'borderTopWidth');
|
||||
}
|
||||
static getBorderBottomWidth(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'border-bottom-width', 'borderBottomWidth');
|
||||
}
|
||||
|
||||
getMarginLeft: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'margin-left', 'marginLeft');
|
||||
},
|
||||
getMarginTop: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'margin-top', 'marginTop');
|
||||
},
|
||||
getMarginRight: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'margin-right', 'marginRight');
|
||||
},
|
||||
getMarginBottom: function (element: HTMLElement): number {
|
||||
return getDimension(element, 'margin-bottom', 'marginBottom');
|
||||
},
|
||||
__commaSentinel: false
|
||||
};
|
||||
static getPaddingLeft(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'padding-left', 'paddingLeft');
|
||||
}
|
||||
static getPaddingRight(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'padding-right', 'paddingRight');
|
||||
}
|
||||
static getPaddingTop(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'padding-top', 'paddingTop');
|
||||
}
|
||||
static getPaddingBottom(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'padding-bottom', 'paddingBottom');
|
||||
}
|
||||
|
||||
static getMarginLeft(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'margin-left', 'marginLeft');
|
||||
}
|
||||
static getMarginTop(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'margin-top', 'marginTop');
|
||||
}
|
||||
static getMarginRight(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'margin-right', 'marginRight');
|
||||
}
|
||||
static getMarginBottom(element: HTMLElement): number {
|
||||
return SizeUtils.getDimension(element, 'margin-bottom', 'marginBottom');
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------------------
|
||||
// Position & Dimension
|
||||
@@ -594,8 +590,8 @@ export function getTopLeftOffset(element: HTMLElement): { left: number; top: num
|
||||
}
|
||||
|
||||
if (element === offsetParent) {
|
||||
left += sizeUtils.getBorderLeftWidth(element);
|
||||
top += sizeUtils.getBorderTopWidth(element);
|
||||
left += SizeUtils.getBorderLeftWidth(element);
|
||||
top += SizeUtils.getBorderTopWidth(element);
|
||||
top += element.offsetTop;
|
||||
left += element.offsetLeft;
|
||||
offsetParent = element.offsetParent;
|
||||
@@ -686,33 +682,33 @@ export const StandardWindow: IStandardWindow = new class implements IStandardWin
|
||||
// Adapted from WinJS
|
||||
// Gets the width of the element, including margins.
|
||||
export function getTotalWidth(element: HTMLElement): number {
|
||||
let margin = sizeUtils.getMarginLeft(element) + sizeUtils.getMarginRight(element);
|
||||
let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element);
|
||||
return element.offsetWidth + margin;
|
||||
}
|
||||
|
||||
export function getContentWidth(element: HTMLElement): number {
|
||||
let border = sizeUtils.getBorderLeftWidth(element) + sizeUtils.getBorderRightWidth(element);
|
||||
let padding = sizeUtils.getPaddingLeft(element) + sizeUtils.getPaddingRight(element);
|
||||
let border = SizeUtils.getBorderLeftWidth(element) + SizeUtils.getBorderRightWidth(element);
|
||||
let padding = SizeUtils.getPaddingLeft(element) + SizeUtils.getPaddingRight(element);
|
||||
return element.offsetWidth - border - padding;
|
||||
}
|
||||
|
||||
export function getTotalScrollWidth(element: HTMLElement): number {
|
||||
let margin = sizeUtils.getMarginLeft(element) + sizeUtils.getMarginRight(element);
|
||||
let margin = SizeUtils.getMarginLeft(element) + SizeUtils.getMarginRight(element);
|
||||
return element.scrollWidth + margin;
|
||||
}
|
||||
|
||||
// Adapted from WinJS
|
||||
// Gets the height of the content of the specified element. The content height does not include borders or padding.
|
||||
export function getContentHeight(element: HTMLElement): number {
|
||||
let border = sizeUtils.getBorderTopWidth(element) + sizeUtils.getBorderBottomWidth(element);
|
||||
let padding = sizeUtils.getPaddingTop(element) + sizeUtils.getPaddingBottom(element);
|
||||
let border = SizeUtils.getBorderTopWidth(element) + SizeUtils.getBorderBottomWidth(element);
|
||||
let padding = SizeUtils.getPaddingTop(element) + SizeUtils.getPaddingBottom(element);
|
||||
return element.offsetHeight - border - padding;
|
||||
}
|
||||
|
||||
// Adapted from WinJS
|
||||
// Gets the height of the element, including its margins.
|
||||
export function getTotalHeight(element: HTMLElement): number {
|
||||
let margin = sizeUtils.getMarginTop(element) + sizeUtils.getMarginBottom(element);
|
||||
let margin = SizeUtils.getMarginTop(element) + SizeUtils.getMarginBottom(element);
|
||||
return element.offsetHeight + margin;
|
||||
}
|
||||
|
||||
@@ -836,53 +832,53 @@ export function isHTMLElement(o: any): o is HTMLElement {
|
||||
|
||||
export const EventType = {
|
||||
// Mouse
|
||||
CLICK: 'click' as 'click',
|
||||
DBLCLICK: 'dblclick' as 'dblclick',
|
||||
MOUSE_UP: 'mouseup' as 'mouseup',
|
||||
MOUSE_DOWN: 'mousedown' as 'mousedown',
|
||||
MOUSE_OVER: 'mouseover' as 'mouseover',
|
||||
MOUSE_MOVE: 'mousemove' as 'mousemove',
|
||||
MOUSE_OUT: 'mouseout' as 'mouseout',
|
||||
MOUSE_ENTER: 'mouseenter' as 'mouseenter',
|
||||
MOUSE_LEAVE: 'mouseleave' as 'mouseleave',
|
||||
CONTEXT_MENU: 'contextmenu' as 'contextmenu',
|
||||
WHEEL: 'wheel' as 'wheel',
|
||||
CLICK: 'click',
|
||||
DBLCLICK: 'dblclick',
|
||||
MOUSE_UP: 'mouseup',
|
||||
MOUSE_DOWN: 'mousedown',
|
||||
MOUSE_OVER: 'mouseover',
|
||||
MOUSE_MOVE: 'mousemove',
|
||||
MOUSE_OUT: 'mouseout',
|
||||
MOUSE_ENTER: 'mouseenter',
|
||||
MOUSE_LEAVE: 'mouseleave',
|
||||
CONTEXT_MENU: 'contextmenu',
|
||||
WHEEL: 'wheel',
|
||||
// Keyboard
|
||||
KEY_DOWN: 'keydown' as 'keydown',
|
||||
KEY_PRESS: 'keypress' as 'keypress',
|
||||
KEY_UP: 'keyup' as 'keyup',
|
||||
KEY_DOWN: 'keydown',
|
||||
KEY_PRESS: 'keypress',
|
||||
KEY_UP: 'keyup',
|
||||
// HTML Document
|
||||
LOAD: 'load' as 'load',
|
||||
UNLOAD: 'unload' as 'unload',
|
||||
ABORT: 'abort' as 'abort',
|
||||
ERROR: 'error' as 'error',
|
||||
RESIZE: 'resize' as 'resize',
|
||||
SCROLL: 'scroll' as 'scroll',
|
||||
LOAD: 'load',
|
||||
UNLOAD: 'unload',
|
||||
ABORT: 'abort',
|
||||
ERROR: 'error',
|
||||
RESIZE: 'resize',
|
||||
SCROLL: 'scroll',
|
||||
// Form
|
||||
SELECT: 'select' as 'select',
|
||||
CHANGE: 'change' as 'change',
|
||||
SUBMIT: 'submit' as 'submit',
|
||||
RESET: 'reset' as 'reset',
|
||||
FOCUS: 'focus' as 'focus',
|
||||
FOCUS_IN: 'focusin' as 'focusin',
|
||||
FOCUS_OUT: 'focusout' as 'focusout',
|
||||
BLUR: 'blur' as 'blur',
|
||||
INPUT: 'input' as 'input',
|
||||
SELECT: 'select',
|
||||
CHANGE: 'change',
|
||||
SUBMIT: 'submit',
|
||||
RESET: 'reset',
|
||||
FOCUS: 'focus',
|
||||
FOCUS_IN: 'focusin',
|
||||
FOCUS_OUT: 'focusout',
|
||||
BLUR: 'blur',
|
||||
INPUT: 'input',
|
||||
// Local Storage
|
||||
STORAGE: 'storage' as 'storage',
|
||||
STORAGE: 'storage',
|
||||
// Drag
|
||||
DRAG_START: 'dragstart' as 'dragstart',
|
||||
DRAG: 'drag' as 'drag',
|
||||
DRAG_ENTER: 'dragenter' as 'dragenter',
|
||||
DRAG_LEAVE: 'dragleave' as 'dragleave',
|
||||
DRAG_OVER: 'dragover' as 'dragover',
|
||||
DROP: 'drop' as 'drop',
|
||||
DRAG_END: 'dragend' as 'dragend',
|
||||
DRAG_START: 'dragstart',
|
||||
DRAG: 'drag',
|
||||
DRAG_ENTER: 'dragenter',
|
||||
DRAG_LEAVE: 'dragleave',
|
||||
DRAG_OVER: 'dragover',
|
||||
DROP: 'drop',
|
||||
DRAG_END: 'dragend',
|
||||
// Animation
|
||||
ANIMATION_START: browser.isWebKit ? 'webkitAnimationStart' : 'animationstart',
|
||||
ANIMATION_END: browser.isWebKit ? 'webkitAnimationEnd' : 'animationend',
|
||||
ANIMATION_ITERATION: browser.isWebKit ? 'webkitAnimationIteration' : 'animationiteration'
|
||||
};
|
||||
} as const;
|
||||
|
||||
export interface EventLike {
|
||||
preventDefault(): void;
|
||||
|
||||
@@ -214,10 +214,10 @@ export class Gesture extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
private newGestureEvent(type: string, intialTarget?: EventTarget): GestureEvent {
|
||||
private newGestureEvent(type: string, initialTarget?: EventTarget): GestureEvent {
|
||||
let event = <GestureEvent>(<any>document.createEvent('CustomEvent'));
|
||||
event.initEvent(type, false, true);
|
||||
event.initialTarget = intialTarget;
|
||||
event.initialTarget = initialTarget;
|
||||
return event;
|
||||
}
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ export class BreadcrumbsWidget {
|
||||
this._pendingLayout.dispose();
|
||||
}
|
||||
if (dim) {
|
||||
// only meaure
|
||||
// only measure
|
||||
this._pendingLayout = this._updateDimensions(dim);
|
||||
} else {
|
||||
this._pendingLayout = this._updateScrollbar();
|
||||
|
||||
@@ -15,6 +15,10 @@
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .dialog-modal-block.dimmed {
|
||||
background: rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
/** Dialog: Container */
|
||||
.monaco-workbench .dialog-box {
|
||||
display: flex;
|
||||
@@ -56,16 +60,22 @@
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
padding: 10px 15px 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.monaco-workbench .dialog-box .dialog-message-row .dialog-icon {
|
||||
flex: 0 0 30px;
|
||||
height: 30px;
|
||||
padding-right: 4px;
|
||||
padding-left: 4px;
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending {
|
||||
background-image: url('pending.svg');
|
||||
}
|
||||
|
||||
.vs .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info {
|
||||
background-image: url('info.svg');
|
||||
}
|
||||
@@ -78,6 +88,10 @@
|
||||
background-image: url('error.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending {
|
||||
background-image: url('pending-dark.svg');
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info,
|
||||
.hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-info {
|
||||
background-image: url('info-inverse.svg');
|
||||
@@ -93,6 +107,14 @@
|
||||
background-image: url('error-inverse.svg');
|
||||
}
|
||||
|
||||
.hc-black .monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending {
|
||||
background-image: url('pending-hc.svg');
|
||||
}
|
||||
|
||||
.monaco-workbench .dialog-box .dialog-message-row .dialog-icon.icon-pending {
|
||||
background-size: 30px;
|
||||
}
|
||||
|
||||
/** Dialog: Message Container */
|
||||
.monaco-workbench .dialog-box .dialog-message-row .dialog-message-container {
|
||||
display: flex;
|
||||
|
||||
@@ -19,7 +19,7 @@ import { mnemonicButtonLabel } from 'vs/base/common/labels';
|
||||
export interface IDialogOptions {
|
||||
cancelId?: number;
|
||||
detail?: string;
|
||||
type?: 'none' | 'info' | 'error' | 'question' | 'warning';
|
||||
type?: 'none' | 'info' | 'error' | 'question' | 'warning' | 'pending';
|
||||
}
|
||||
|
||||
export interface IDialogStyles extends IButtonStyles {
|
||||
@@ -33,6 +33,7 @@ export class Dialog extends Disposable {
|
||||
private element: HTMLElement | undefined;
|
||||
private modal: HTMLElement | undefined;
|
||||
private buttonsContainer: HTMLElement | undefined;
|
||||
private messageDetailElement: HTMLElement | undefined;
|
||||
private iconElement: HTMLElement | undefined;
|
||||
private toolbarContainer: HTMLElement | undefined;
|
||||
private buttonGroup: ButtonGroup | undefined;
|
||||
@@ -40,7 +41,7 @@ export class Dialog extends Disposable {
|
||||
|
||||
constructor(private container: HTMLElement, private message: string, private buttons: string[], private options: IDialogOptions) {
|
||||
super();
|
||||
this.modal = this.container.appendChild($('.dialog-modal-block'));
|
||||
this.modal = this.container.appendChild($(`.dialog-modal-block${options.type === 'pending' ? '.dimmed' : ''}`));
|
||||
this.element = this.modal.appendChild($('.dialog-box'));
|
||||
hide(this.element);
|
||||
|
||||
@@ -56,13 +57,19 @@ export class Dialog extends Disposable {
|
||||
messageElement.innerText = this.message;
|
||||
}
|
||||
|
||||
const messageDetailElement = messageContainer.appendChild($('.dialog-message-detail'));
|
||||
messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
|
||||
this.messageDetailElement = messageContainer.appendChild($('.dialog-message-detail'));
|
||||
this.messageDetailElement.innerText = this.options.detail ? this.options.detail : message;
|
||||
|
||||
const toolbarRowElement = this.element.appendChild($('.dialog-toolbar-row'));
|
||||
this.toolbarContainer = toolbarRowElement.appendChild($('.dialog-toolbar'));
|
||||
}
|
||||
|
||||
updateMessage(message: string): void {
|
||||
if (this.messageDetailElement) {
|
||||
this.messageDetailElement.innerText = message;
|
||||
}
|
||||
}
|
||||
|
||||
async show(): Promise<number> {
|
||||
return new Promise<number>((resolve) => {
|
||||
if (!this.element || !this.buttonsContainer || !this.iconElement || !this.toolbarContainer) {
|
||||
@@ -129,6 +136,9 @@ export class Dialog extends Disposable {
|
||||
case 'warning':
|
||||
addClass(this.iconElement, 'icon-warning');
|
||||
break;
|
||||
case 'pending':
|
||||
addClass(this.iconElement, 'icon-pending');
|
||||
break;
|
||||
case 'none':
|
||||
case 'info':
|
||||
case 'question':
|
||||
|
||||
31
src/vs/base/browser/ui/dialog/pending-dark.svg
Normal file
31
src/vs/base/browser/ui/dialog/pending-dark.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:grey;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
31
src/vs/base/browser/ui/dialog/pending-hc.svg
Normal file
31
src/vs/base/browser/ui/dialog/pending-hc.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g style="fill:white;">
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
31
src/vs/base/browser/ui/dialog/pending.svg
Normal file
31
src/vs/base/browser/ui/dialog/pending.svg
Normal file
@@ -0,0 +1,31 @@
|
||||
<?xml version='1.0' standalone='no' ?>
|
||||
<svg xmlns='http://www.w3.org/2000/svg' version='1.1' width='10px' height='10px'>
|
||||
<style>
|
||||
circle {
|
||||
animation: ball 1.04s linear infinite;
|
||||
}
|
||||
|
||||
circle:nth-child(2) { animation-delay: 0.13s; }
|
||||
circle:nth-child(3) { animation-delay: 0.26s; }
|
||||
circle:nth-child(4) { animation-delay: 0.39s; }
|
||||
circle:nth-child(5) { animation-delay: 0.52s; }
|
||||
circle:nth-child(6) { animation-delay: 0.65s; }
|
||||
circle:nth-child(7) { animation-delay: 0.78s; }
|
||||
circle:nth-child(8) { animation-delay: 0.91s; }
|
||||
|
||||
@keyframes ball {
|
||||
from { opacity: 1; }
|
||||
to { opacity: 0.3; }
|
||||
}
|
||||
</style>
|
||||
<g>
|
||||
<circle cx='5' cy='1' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
<circle cx='9' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='7.8284' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='5' cy='9' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='7.8284' r='1' style='opacity:0.3;' />
|
||||
<circle cx='1' cy='5' r='1' style='opacity:0.3;' />
|
||||
<circle cx='2.1716' cy='2.1716' r='1' style='opacity:0.3;' />
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 1.1 KiB |
@@ -502,7 +502,7 @@ function isMouseRightClick(event: UIEvent): boolean {
|
||||
return event instanceof MouseEvent && event.button === 2;
|
||||
}
|
||||
|
||||
const DefaultMultipleSelectionContoller = {
|
||||
const DefaultMultipleSelectionController = {
|
||||
isSelectionSingleChangeEvent,
|
||||
isSelectionRangeChangeEvent
|
||||
};
|
||||
@@ -529,7 +529,7 @@ export class MouseController<T> implements IDisposable {
|
||||
this.multipleSelectionSupport = !(list.options.multipleSelectionSupport === false);
|
||||
|
||||
if (this.multipleSelectionSupport) {
|
||||
this.multipleSelectionController = list.options.multipleSelectionController || DefaultMultipleSelectionContoller;
|
||||
this.multipleSelectionController = list.options.multipleSelectionController || DefaultMultipleSelectionController;
|
||||
}
|
||||
|
||||
this.openController = list.options.openController || DefaultOpenController;
|
||||
@@ -909,7 +909,7 @@ function getContiguousRangeContaining(range: number[], value: number): number[]
|
||||
|
||||
/**
|
||||
* Given two sorted collections of numbers, returns the intersection
|
||||
* betweem them (OR).
|
||||
* between them (OR).
|
||||
*/
|
||||
function disjunction(one: number[], other: number[]): number[] {
|
||||
const result: number[] = [];
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
@font-face {
|
||||
font-family: "octicons";
|
||||
src: url("./octicons.ttf?4cd2299755e93a2430ba5703f4476584") format("truetype"),
|
||||
url("./octicons.svg?4cd2299755e93a2430ba5703f4476584#octicons") format("svg");
|
||||
src: url("./octicons.ttf?91284a5a76ea88faeb754359b7f7cd03") format("truetype"),
|
||||
url("./octicons.svg?91284a5a76ea88faeb754359b7f7cd03#octicons") format("svg");
|
||||
}
|
||||
|
||||
.octicon, .mega-octicon {
|
||||
@@ -240,4 +240,5 @@ url("./octicons.svg?4cd2299755e93a2430ba5703f4476584#octicons") format("svg");
|
||||
.octicon-fold-up:before { content: "\f105" }
|
||||
.octicon-github-action:before { content: "\f106" }
|
||||
.octicon-play:before { content: "\f107" }
|
||||
.octicon-request-changes:before { content: "\f108" }
|
||||
.octicon-remote:before { content: "\f108" }
|
||||
.octicon-request-changes:before { content: "\f109" }
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 131 KiB After Width: | Height: | Size: 127 KiB |
Binary file not shown.
@@ -523,7 +523,7 @@ export class DomScrollableElement extends ScrollableElement {
|
||||
}
|
||||
|
||||
public scanDomNode(): void {
|
||||
// widh, scrollLeft, scrollWidth, height, scrollTop, scrollHeight
|
||||
// width, scrollLeft, scrollWidth, height, scrollTop, scrollHeight
|
||||
this.setScrollDimensions({
|
||||
width: this._element.clientWidth,
|
||||
scrollWidth: this._element.scrollWidth,
|
||||
|
||||
@@ -33,7 +33,7 @@ export const enum TreeVisibility {
|
||||
export interface ITreeFilterDataResult<TFilterData> {
|
||||
|
||||
/**
|
||||
* Whether the node should be visibile.
|
||||
* Whether the node should be visible.
|
||||
*/
|
||||
visibility: boolean | TreeVisibility;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
import { ParseError, Node, JSONPath, Segment, parseTree, findNodeAtLocation } from './json';
|
||||
import { Edit, format, isEOL, FormattingOptions } from './jsonFormatter';
|
||||
import { mergeSort } from 'vs/base/common/arrays';
|
||||
|
||||
|
||||
export function removeProperty(text: string, path: JSONPath, formattingOptions: FormattingOptions): Edit[] {
|
||||
@@ -158,6 +159,27 @@ export function applyEdit(text: string, edit: Edit): string {
|
||||
return text.substring(0, edit.offset) + edit.content + text.substring(edit.offset + edit.length);
|
||||
}
|
||||
|
||||
export function applyEdits(text: string, edits: Edit[]): string {
|
||||
let sortedEdits = mergeSort(edits, (a, b) => {
|
||||
const diff = a.offset - b.offset;
|
||||
if (diff === 0) {
|
||||
return a.length - b.length;
|
||||
}
|
||||
return diff;
|
||||
});
|
||||
let lastModifiedOffset = text.length;
|
||||
for (let i = sortedEdits.length - 1; i >= 0; i--) {
|
||||
let e = sortedEdits[i];
|
||||
if (e.offset + e.length <= lastModifiedOffset) {
|
||||
text = applyEdit(text, e);
|
||||
} else {
|
||||
throw new Error('Overlapping edit');
|
||||
}
|
||||
lastModifiedOffset = e.offset;
|
||||
}
|
||||
return text;
|
||||
}
|
||||
|
||||
export function isWS(text: string, offset: number) {
|
||||
return '\r\n \t'.indexOf(text.charAt(offset)) !== -1;
|
||||
}
|
||||
@@ -226,7 +226,7 @@ export class URI implements UriComponents {
|
||||
|
||||
// ---- modify to new -------------------------
|
||||
|
||||
public with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
|
||||
with(change: { scheme?: string; authority?: string | null; path?: string | null; query?: string | null; fragment?: string | null }): URI {
|
||||
|
||||
if (!change) {
|
||||
return this;
|
||||
@@ -279,7 +279,7 @@ export class URI implements UriComponents {
|
||||
*
|
||||
* @param value A string which represents an URI (see `URI#toString`).
|
||||
*/
|
||||
public static parse(value: string, _strict: boolean = false): URI {
|
||||
static parse(value: string, _strict: boolean = false): URI {
|
||||
const match = _regexp.exec(value);
|
||||
if (!match) {
|
||||
return new _URI(_empty, _empty, _empty, _empty, _empty);
|
||||
@@ -315,7 +315,7 @@ export class URI implements UriComponents {
|
||||
*
|
||||
* @param path A file system path (see `URI#fsPath`)
|
||||
*/
|
||||
public static file(path: string): URI {
|
||||
static file(path: string): URI {
|
||||
|
||||
let authority = _empty;
|
||||
|
||||
@@ -342,7 +342,7 @@ export class URI implements UriComponents {
|
||||
return new _URI('file', authority, path, _empty, _empty);
|
||||
}
|
||||
|
||||
public static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
static from(components: { scheme: string; authority?: string; path?: string; query?: string; fragment?: string }): URI {
|
||||
return new _URI(
|
||||
components.scheme,
|
||||
components.authority,
|
||||
@@ -365,17 +365,22 @@ export class URI implements UriComponents {
|
||||
*
|
||||
* @param skipEncoding Do not encode the result, default is `false`
|
||||
*/
|
||||
public toString(skipEncoding: boolean = false): string {
|
||||
toString(skipEncoding: boolean = false): string {
|
||||
return _asFormatted(this, skipEncoding);
|
||||
}
|
||||
|
||||
public toJSON(): object {
|
||||
toJSON(): UriComponents {
|
||||
return this;
|
||||
}
|
||||
|
||||
static revive(data: UriComponents | any): URI {
|
||||
static revive(data: UriComponents | URI): URI;
|
||||
static revive(data: UriComponents | URI | undefined): URI | undefined;
|
||||
static revive(data: UriComponents | URI | null): URI | null;
|
||||
static revive(data: UriComponents | URI | undefined | null): URI | undefined | null;
|
||||
static revive(data: UriComponents | URI | undefined | null): URI | undefined | null {
|
||||
if (!data) {
|
||||
return data;
|
||||
// {{SQL CARBON EDIT}} @todo chlafren change back to data when we enable strict null checks
|
||||
return undefined;
|
||||
} else if (data instanceof URI) {
|
||||
return data;
|
||||
} else {
|
||||
@@ -415,7 +420,7 @@ class _URI extends URI {
|
||||
return this._fsPath;
|
||||
}
|
||||
|
||||
public toString(skipEncoding: boolean = false): string {
|
||||
toString(skipEncoding: boolean = false): string {
|
||||
if (!skipEncoding) {
|
||||
if (!this._formatted) {
|
||||
this._formatted = _asFormatted(this, false);
|
||||
@@ -427,7 +432,7 @@ class _URI extends URI {
|
||||
}
|
||||
}
|
||||
|
||||
toJSON(): object {
|
||||
toJSON(): UriComponents {
|
||||
const res = <UriState>{
|
||||
$mid: 1
|
||||
};
|
||||
|
||||
@@ -14,6 +14,10 @@ export const UTF8_with_bom = 'utf8bom';
|
||||
export const UTF16be = 'utf16be';
|
||||
export const UTF16le = 'utf16le';
|
||||
|
||||
export const UTF16be_BOM = [0xFE, 0xFF];
|
||||
export const UTF16le_BOM = [0xFF, 0xFE];
|
||||
export const UTF8_BOM = [0xEF, 0xBB, 0xBF];
|
||||
|
||||
export interface IDecodeStreamOptions {
|
||||
guessEncoding?: boolean;
|
||||
minBytesRequiredForDetection?: number;
|
||||
@@ -150,12 +154,12 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | null, bytesRead:
|
||||
const b1 = buffer.readUInt8(1);
|
||||
|
||||
// UTF-16 BE
|
||||
if (b0 === 0xFE && b1 === 0xFF) {
|
||||
if (b0 === UTF16be_BOM[0] && b1 === UTF16be_BOM[1]) {
|
||||
return UTF16be;
|
||||
}
|
||||
|
||||
// UTF-16 LE
|
||||
if (b0 === 0xFF && b1 === 0xFE) {
|
||||
if (b0 === UTF16le_BOM[0] && b1 === UTF16le_BOM[1]) {
|
||||
return UTF16le;
|
||||
}
|
||||
|
||||
@@ -166,7 +170,7 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | null, bytesRead:
|
||||
const b2 = buffer.readUInt8(2);
|
||||
|
||||
// UTF-8
|
||||
if (b0 === 0xEF && b1 === 0xBB && b2 === 0xBF) {
|
||||
if (b0 === UTF8_BOM[0] && b1 === UTF8_BOM[1] && b2 === UTF8_BOM[2]) {
|
||||
return UTF8;
|
||||
}
|
||||
|
||||
@@ -178,7 +182,7 @@ export function detectEncodingByBOMFromBuffer(buffer: Buffer | null, bytesRead:
|
||||
* If no BOM is detected, null will be passed to callback.
|
||||
*/
|
||||
export function detectEncodingByBOM(file: string): Promise<string | null> {
|
||||
return stream.readExactlyByFile(file, 3).then(({ buffer, bytesRead }) => detectEncodingByBOMFromBuffer(buffer, bytesRead));
|
||||
return stream.readExactlyByFile(file, 3).then(({ buffer, bytesRead }) => detectEncodingByBOMFromBuffer(buffer, bytesRead), error => null);
|
||||
}
|
||||
|
||||
const MINIMUM_THRESHOLD = 0.2;
|
||||
|
||||
39
src/vs/base/node/ps.sh
Executable file
39
src/vs/base/node/ps.sh
Executable file
@@ -0,0 +1,39 @@
|
||||
#!/bin/sh
|
||||
PAGESIZE=`getconf PAGESIZE`;
|
||||
TOTAL_MEMORY=`cat /proc/meminfo | head -n 1 | awk '{print $2}'`;
|
||||
|
||||
# Mimic the output of ps -ax -o pid=,ppid=,pcpu=,pmem=,command=
|
||||
# Read all numeric subdirectories in /proc
|
||||
for pid in `cd /proc && ls -d [0-9]*`
|
||||
do {
|
||||
if [ -e /proc/$pid/stat ]
|
||||
then
|
||||
echo $pid;
|
||||
|
||||
# ppid is the word at index 4 in the stat file for the process
|
||||
awk '{print $4}' /proc/$pid/stat;
|
||||
|
||||
# pcpu - calculation will be done later, this is a placeholder value
|
||||
echo "0.0"
|
||||
|
||||
# pmem - ratio of the process's working set size to total memory.
|
||||
# use the page size to convert to bytes, total memory is in KB
|
||||
# multiplied by 100 to get percentage, extra 10 to be able to move
|
||||
# the decimal over by one place
|
||||
RESIDENT_SET_SIZE=`awk '{print $24}' /proc/$pid/stat`;
|
||||
PERCENT_MEMORY=$(((1000 * $PAGESIZE * $RESIDENT_SET_SIZE) / ($TOTAL_MEMORY * 1024)));
|
||||
if [ $PERCENT_MEMORY -lt 10 ]
|
||||
then
|
||||
# replace the last character with 0. the last character
|
||||
echo $PERCENT_MEMORY | sed 's/.$/0.&/'; #pmem
|
||||
else
|
||||
# insert . before the last character
|
||||
echo $PERCENT_MEMORY | sed 's/.$/.&/';
|
||||
fi
|
||||
|
||||
# cmdline
|
||||
xargs -0 < /proc/$pid/cmdline;
|
||||
fi
|
||||
} | tr "\n" "\t"; # Replace newlines with tab so that all info for a process is shown on one line
|
||||
echo; # But add new lines between processes
|
||||
done
|
||||
@@ -14,6 +14,7 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
let rootItem: ProcessItem | undefined;
|
||||
const map = new Map<number, ProcessItem>();
|
||||
|
||||
|
||||
function addToTree(pid: number, ppid: number, cmd: string, load: number, mem: number) {
|
||||
|
||||
const parent = map.get(ppid);
|
||||
@@ -162,64 +163,87 @@ export function listProcesses(rootPid: number): Promise<ProcessItem> {
|
||||
}, windowsProcessTree.ProcessDataFlag.CommandLine | windowsProcessTree.ProcessDataFlag.Memory);
|
||||
});
|
||||
} else { // OS X & Linux
|
||||
|
||||
const CMD = '/bin/ps -ax -o pid=,ppid=,pcpu=,pmem=,command=';
|
||||
const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/;
|
||||
|
||||
// Set numeric locale to ensure '.' is used as the decimal separator
|
||||
exec(CMD, { maxBuffer: 1000 * 1024, env: { LC_NUMERIC: 'en_US.UTF-8' } }, (err, stdout, stderr) => {
|
||||
|
||||
if (err || stderr) {
|
||||
reject(err || new Error(stderr.toString()));
|
||||
} else {
|
||||
|
||||
const lines = stdout.toString().split('\n');
|
||||
for (const line of lines) {
|
||||
const matches = PID_CMD.exec(line.trim());
|
||||
if (matches && matches.length === 6) {
|
||||
addToTree(parseInt(matches[1]), parseInt(matches[2]), matches[5], parseFloat(matches[3]), parseFloat(matches[4]));
|
||||
function calculateLinuxCpuUsage() {
|
||||
// Flatten rootItem to get a list of all VSCode processes
|
||||
let processes = [rootItem];
|
||||
const pids: number[] = [];
|
||||
while (processes.length) {
|
||||
const process = processes.shift();
|
||||
if (process) {
|
||||
pids.push(process.pid);
|
||||
if (process.children) {
|
||||
processes = processes.concat(process.children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
// Flatten rootItem to get a list of all VSCode processes
|
||||
let processes = [rootItem];
|
||||
const pids: number[] = [];
|
||||
while (processes.length) {
|
||||
const process = processes.shift();
|
||||
if (process) {
|
||||
pids.push(process.pid);
|
||||
if (process.children) {
|
||||
processes = processes.concat(process.children);
|
||||
}
|
||||
}
|
||||
// The cpu usage value reported on Linux is the average over the process lifetime,
|
||||
// recalculate the usage over a one second interval
|
||||
// JSON.stringify is needed to escape spaces, https://github.com/nodejs/node/issues/6803
|
||||
let cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/cpuUsage.sh'));
|
||||
cmd += ' ' + pids.join(' ');
|
||||
|
||||
exec(cmd, {}, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
reject(err || new Error(stderr.toString()));
|
||||
} else {
|
||||
const cpuUsage = stdout.toString().split('\n');
|
||||
for (let i = 0; i < pids.length; i++) {
|
||||
const processInfo = map.get(pids[i])!;
|
||||
processInfo.load = parseFloat(cpuUsage[i]);
|
||||
}
|
||||
|
||||
// The cpu usage value reported on Linux is the average over the process lifetime,
|
||||
// recalculate the usage over a one second interval
|
||||
// JSON.stringify is needed to escape spaces, https://github.com/nodejs/node/issues/6803
|
||||
let cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/cpuUsage.sh'));
|
||||
cmd += ' ' + pids.join(' ');
|
||||
resolve(rootItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
exec('which ps', {}, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
if (process.platform !== 'linux') {
|
||||
reject(err || new Error(stderr.toString()));
|
||||
} else {
|
||||
const cmd = JSON.stringify(getPathFromAmdModule(require, 'vs/base/node/ps.sh'));
|
||||
exec(cmd, {}, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
reject(err || new Error(stderr.toString()));
|
||||
} else {
|
||||
const cpuUsage = stdout.toString().split('\n');
|
||||
for (let i = 0; i < pids.length; i++) {
|
||||
const processInfo = map.get(pids[i])!;
|
||||
processInfo.load = parseFloat(cpuUsage[i]);
|
||||
}
|
||||
|
||||
resolve(rootItem);
|
||||
parsePsOutput(stdout, addToTree);
|
||||
calculateLinuxCpuUsage();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
resolve(rootItem);
|
||||
}
|
||||
} else {
|
||||
const ps = stdout.toString().trim();
|
||||
const args = '-ax -o pid=,ppid=,pcpu=,pmem=,command=';
|
||||
|
||||
// Set numeric locale to ensure '.' is used as the decimal separator
|
||||
exec(`${ps} ${args}`, { maxBuffer: 1000 * 1024, env: { LC_NUMERIC: 'en_US.UTF-8' } }, (err, stdout, stderr) => {
|
||||
if (err || stderr) {
|
||||
reject(err || new Error(stderr.toString()));
|
||||
} else {
|
||||
parsePsOutput(stdout, addToTree);
|
||||
|
||||
if (process.platform === 'linux') {
|
||||
calculateLinuxCpuUsage();
|
||||
} else {
|
||||
resolve(rootItem);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function parsePsOutput(stdout: string, addToTree: (pid: number, ppid: number, cmd: string, load: number, mem: number) => void): void {
|
||||
const PID_CMD = /^\s*([0-9]+)\s+([0-9]+)\s+([0-9]+\.[0-9]+)\s+([0-9]+\.[0-9]+)\s+(.+)$/;
|
||||
const lines = stdout.toString().split('\n');
|
||||
for (const line of lines) {
|
||||
const matches = PID_CMD.exec(line.trim());
|
||||
if (matches && matches.length === 6) {
|
||||
addToTree(parseInt(matches[1]), parseInt(matches[2]), matches[5], parseFloat(matches[3]), parseFloat(matches[4]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
import * as assert from 'assert';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { isWindows } from 'vs/base/common/platform';
|
||||
|
||||
|
||||
@@ -441,7 +441,7 @@ suite('URI', () => {
|
||||
// let c = 100000;
|
||||
// while (c-- > 0) {
|
||||
for (let value of values) {
|
||||
let data = value.toJSON();
|
||||
let data = value.toJSON() as UriComponents;
|
||||
let clone = URI.revive(data);
|
||||
|
||||
assert.equal(clone.scheme, value.scheme);
|
||||
|
||||
@@ -11,6 +11,14 @@ import { Readable } from 'stream';
|
||||
import { getPathFromAmdModule } from 'vs/base/common/amd';
|
||||
|
||||
suite('Encoding', () => {
|
||||
|
||||
test('detectBOM does not return error for non existing file', async () => {
|
||||
const file = getPathFromAmdModule(require, './fixtures/not-exist.css');
|
||||
|
||||
const detectedEncoding = await encoding.detectEncodingByBOM(file);
|
||||
assert.equal(detectedEncoding, null);
|
||||
});
|
||||
|
||||
test('detectBOM UTF-8', async () => {
|
||||
const file = getPathFromAmdModule(require, './fixtures/some_utf8.css');
|
||||
|
||||
|
||||
@@ -8,7 +8,8 @@ import { getMachineId } from 'vs/base/node/id';
|
||||
|
||||
suite('ID', () => {
|
||||
|
||||
test('getMachineId', () => {
|
||||
test('getMachineId', function () {
|
||||
this.timeout(20000);
|
||||
return getMachineId().then(id => {
|
||||
assert.ok(id);
|
||||
});
|
||||
|
||||
@@ -60,6 +60,7 @@ export function startup(configuration: IssueReporterConfiguration) {
|
||||
const issueReporter = new IssueReporter(configuration);
|
||||
issueReporter.render();
|
||||
document.body.style.display = 'block';
|
||||
issueReporter.setInitialFocus();
|
||||
}
|
||||
|
||||
export class IssueReporter extends Disposable {
|
||||
@@ -88,6 +89,8 @@ export class IssueReporter extends Disposable {
|
||||
os: `${os.type()} ${os.arch()} ${os.release()}${isSnap ? ' snap' : ''}`
|
||||
},
|
||||
extensionsDisabled: !!this.environmentService.disableExtensions,
|
||||
fileOnExtension: configuration.data.extensionId ? true : undefined,
|
||||
selectedExtension: configuration.data.extensionId ? configuration.data.enabledExtensions.filter(extension => extension.id === configuration.data.extensionId)[0] : undefined
|
||||
});
|
||||
|
||||
const issueReporterElement = this.getElementById('issue-reporter');
|
||||
@@ -140,6 +143,21 @@ export class IssueReporter extends Disposable {
|
||||
this.renderBlocks();
|
||||
}
|
||||
|
||||
setInitialFocus() {
|
||||
const { fileOnExtension } = this.issueReporterModel.getData();
|
||||
if (fileOnExtension) {
|
||||
const issueTitle = document.getElementById('issue-title');
|
||||
if (issueTitle) {
|
||||
issueTitle.focus();
|
||||
}
|
||||
} else {
|
||||
const issueType = document.getElementById('issue-type');
|
||||
if (issueType) {
|
||||
issueType.focus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private applyZoom(zoomLevel: number) {
|
||||
webFrame.setZoomLevel(zoomLevel);
|
||||
browser.setZoomFactor(webFrame.getZoomFactor());
|
||||
@@ -699,9 +717,13 @@ export class IssueReporter extends Disposable {
|
||||
|
||||
private setSourceOptions(): void {
|
||||
const sourceSelect = this.getElementById('issue-source')! as HTMLSelectElement;
|
||||
const selected = sourceSelect.selectedIndex;
|
||||
const { issueType, fileOnExtension } = this.issueReporterModel.getData();
|
||||
let selected = sourceSelect.selectedIndex;
|
||||
if (selected === -1 && fileOnExtension !== undefined) {
|
||||
selected = fileOnExtension ? 2 : 1;
|
||||
}
|
||||
|
||||
sourceSelect.innerHTML = '';
|
||||
const { issueType } = this.issueReporterModel.getData();
|
||||
if (issueType === IssueType.FeatureRequest) {
|
||||
sourceSelect.append(...[
|
||||
this.makeOption('', localize('selectSource', "Select source"), true),
|
||||
@@ -961,10 +983,15 @@ export class IssueReporter extends Disposable {
|
||||
return 0;
|
||||
});
|
||||
|
||||
const makeOption = (extension: IOption) => `<option value="${extension.id}">${escape(extension.name)}</option>`;
|
||||
const makeOption = (extension: IOption, selectedExtension?: IssueReporterExtensionData) => {
|
||||
const selected = selectedExtension && extension.id === selectedExtension.id;
|
||||
return `<option value="${extension.id}" ${selected ? 'selected' : ''}>${escape(extension.name)}</option>`;
|
||||
};
|
||||
|
||||
const extensionsSelector = this.getElementById('extension-selector');
|
||||
if (extensionsSelector) {
|
||||
extensionsSelector.innerHTML = '<option></option>' + extensionOptions.map(makeOption).join('\n');
|
||||
const { selectedExtension } = this.issueReporterModel.getData();
|
||||
extensionsSelector.innerHTML = '<option></option>' + extensionOptions.map(extension => makeOption(extension, selectedExtension)).join('\n');
|
||||
|
||||
this.addEventListener('extension-selector', 'change', (e: Event) => {
|
||||
const selectedExtensionId = (<HTMLInputElement>e.target).value;
|
||||
|
||||
@@ -29,8 +29,8 @@ const collapsedStateCache: Map<string, boolean> = new Map<string, boolean>();
|
||||
let lastRequestTime: number;
|
||||
|
||||
interface FormattedProcessItem {
|
||||
cpu: string;
|
||||
memory: string;
|
||||
cpu: number;
|
||||
memory: number;
|
||||
pid: string;
|
||||
name: string;
|
||||
formattedName: string;
|
||||
@@ -66,8 +66,8 @@ function getProcessItem(processes: FormattedProcessItem[], item: ProcessItem, in
|
||||
const formattedName = isRoot ? name : `${repeat(' ', indent)} ${name}`;
|
||||
const memory = process.platform === 'win32' ? item.mem : (totalmem() * (item.mem / 100));
|
||||
processes.push({
|
||||
cpu: item.load.toFixed(0),
|
||||
memory: (memory / MB).toFixed(0),
|
||||
cpu: item.load,
|
||||
memory: (memory / MB),
|
||||
pid: item.pid.toFixed(0),
|
||||
name,
|
||||
formattedName,
|
||||
@@ -202,13 +202,13 @@ function renderTableSection(sectionName: string, processList: FormattedProcessIt
|
||||
p.pid === highestCPUProcess
|
||||
? cpu.classList.add('centered', 'highest')
|
||||
: cpu.classList.add('centered');
|
||||
cpu.textContent = p.cpu.toString();
|
||||
cpu.textContent = p.cpu.toFixed(0);
|
||||
|
||||
const memory = document.createElement('td');
|
||||
p.pid === highestMemoryProcess
|
||||
? memory.classList.add('centered', 'highest')
|
||||
: memory.classList.add('centered');
|
||||
memory.textContent = p.memory;
|
||||
memory.textContent = p.memory.toFixed(0);
|
||||
|
||||
const pid = document.createElement('td');
|
||||
pid.classList.add('centered');
|
||||
|
||||
@@ -1754,7 +1754,7 @@ export class EditorModeContext extends Disposable {
|
||||
this._hasSignatureHelpProvider.set(modes.SignatureHelpProviderRegistry.has(model));
|
||||
this._hasDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.has(model) || modes.DocumentRangeFormattingEditProviderRegistry.has(model));
|
||||
this._hasDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.has(model));
|
||||
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length > 1 || modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
|
||||
this._hasMultipleDocumentFormattingProvider.set(modes.DocumentFormattingEditProviderRegistry.all(model).length + modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
|
||||
this._hasMultipleDocumentSelectionFormattingProvider.set(modes.DocumentRangeFormattingEditProviderRegistry.all(model).length > 1);
|
||||
this._isInWalkThrough.set(model.uri.scheme === Schemas.walkThroughSnippet);
|
||||
});
|
||||
|
||||
@@ -368,9 +368,6 @@ export class ReferenceWidget extends PeekViewWidget {
|
||||
if (e.browserEvent instanceof KeyboardEvent) {
|
||||
// todo@joh make this a command
|
||||
goto = true;
|
||||
} else if (e.browserEvent instanceof MouseEvent) {
|
||||
aside = e.browserEvent.ctrlKey || e.browserEvent.metaKey || e.browserEvent.altKey;
|
||||
goto = e.browserEvent.detail === 2;
|
||||
}
|
||||
if (aside) {
|
||||
onEvent(e.elements[0], 'side');
|
||||
|
||||
@@ -197,7 +197,7 @@ export class SnippetController2 implements IEditorContribution {
|
||||
insertText: option.value,
|
||||
// insertText: `\${1|${after.concat(before).join(',')}|}$0`,
|
||||
// snippetType: 'textmate',
|
||||
sortText: repeat('a', i),
|
||||
sortText: repeat('a', i + 1),
|
||||
range: Range.fromPositions(this._editor.getPosition()!, this._editor.getPosition()!.delta(0, first.value.length))
|
||||
};
|
||||
}));
|
||||
|
||||
@@ -343,7 +343,7 @@ export class SuggestModel implements IDisposable {
|
||||
const position = this._editor.getPosition();
|
||||
const ctx = new LineContext(model, position, this._state === State.Auto, false);
|
||||
this._onNewContext(ctx);
|
||||
}, 25);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
trigger(context: SuggestTriggerContext, retrigger: boolean = false, onlyFrom?: Set<CompletionItemProvider>, existingItems?: CompletionItem[]): void {
|
||||
|
||||
@@ -496,6 +496,9 @@ export class StandaloneTelemetryService implements ITelemetryService {
|
||||
|
||||
public isOptedIn = false;
|
||||
|
||||
public setEnabled(value: boolean): void {
|
||||
}
|
||||
|
||||
public publicLog(eventName: string, data?: any): Promise<void> {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
7
src/vs/monaco.d.ts
vendored
7
src/vs/monaco.d.ts
vendored
@@ -171,8 +171,11 @@ declare namespace monaco {
|
||||
* @param skipEncoding Do not encode the result, default is `false`
|
||||
*/
|
||||
toString(skipEncoding?: boolean): string;
|
||||
toJSON(): object;
|
||||
static revive(data: UriComponents | any): Uri;
|
||||
toJSON(): UriComponents;
|
||||
static revive(data: UriComponents | Uri): Uri;
|
||||
static revive(data: UriComponents | Uri | undefined): Uri | undefined;
|
||||
static revive(data: UriComponents | Uri | null): Uri | null;
|
||||
static revive(data: UriComponents | Uri | undefined | null): Uri | undefined | null;
|
||||
}
|
||||
|
||||
export interface UriComponents {
|
||||
|
||||
@@ -83,8 +83,21 @@ export interface IConfigurationRegistry {
|
||||
}
|
||||
|
||||
export const enum ConfigurationScope {
|
||||
/**
|
||||
* Application specific configuration, which can be configured only in local user settings.
|
||||
*/
|
||||
APPLICATION = 1,
|
||||
/**
|
||||
* Machine specific configuration, which can be configured only in local and remote user settings.
|
||||
*/
|
||||
MACHINE,
|
||||
/**
|
||||
* Window specific configuration, which can be configured in the user or workspace settings.
|
||||
*/
|
||||
WINDOW,
|
||||
/**
|
||||
* Resource specific configuration, which can be configured in the user, workspace or folder settings.
|
||||
*/
|
||||
RESOURCE,
|
||||
}
|
||||
|
||||
@@ -95,6 +108,10 @@ export interface IConfigurationPropertySchema extends IJSONSchema {
|
||||
tags?: string[];
|
||||
}
|
||||
|
||||
export interface IConfigurationExtensionInfo {
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface IConfigurationNode {
|
||||
id?: string;
|
||||
order?: number;
|
||||
@@ -105,7 +122,7 @@ export interface IConfigurationNode {
|
||||
allOf?: IConfigurationNode[];
|
||||
overridable?: boolean;
|
||||
scope?: ConfigurationScope;
|
||||
contributedByExtension?: boolean;
|
||||
extensionInfo?: IConfigurationExtensionInfo;
|
||||
}
|
||||
|
||||
export interface IDefaultConfigurationExtension {
|
||||
@@ -116,6 +133,7 @@ export interface IDefaultConfigurationExtension {
|
||||
|
||||
export const allSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} };
|
||||
export const applicationSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} };
|
||||
export const machineSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} };
|
||||
export const windowSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} };
|
||||
export const resourceSettings: { properties: {}, patternProperties: {} } = { properties: {}, patternProperties: {} };
|
||||
|
||||
@@ -186,6 +204,9 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
case ConfigurationScope.APPLICATION:
|
||||
delete applicationSettings.properties[key];
|
||||
break;
|
||||
case ConfigurationScope.MACHINE:
|
||||
delete machineSettings.properties[key];
|
||||
break;
|
||||
case ConfigurationScope.WINDOW:
|
||||
delete windowSettings.properties[key];
|
||||
break;
|
||||
@@ -334,6 +355,9 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
case ConfigurationScope.APPLICATION:
|
||||
applicationSettings.properties[key] = properties[key];
|
||||
break;
|
||||
case ConfigurationScope.MACHINE:
|
||||
machineSettings.properties[key] = properties[key];
|
||||
break;
|
||||
case ConfigurationScope.WINDOW:
|
||||
windowSettings.properties[key] = properties[key];
|
||||
break;
|
||||
@@ -371,6 +395,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
|
||||
delete allSettings.patternProperties[this.overridePropertyPattern];
|
||||
delete applicationSettings.patternProperties[this.overridePropertyPattern];
|
||||
delete machineSettings.patternProperties[this.overridePropertyPattern];
|
||||
delete windowSettings.patternProperties[this.overridePropertyPattern];
|
||||
delete resourceSettings.patternProperties[this.overridePropertyPattern];
|
||||
|
||||
@@ -378,6 +403,7 @@ class ConfigurationRegistry implements IConfigurationRegistry {
|
||||
|
||||
allSettings.patternProperties[this.overridePropertyPattern] = patternProperties;
|
||||
applicationSettings.patternProperties[this.overridePropertyPattern] = patternProperties;
|
||||
machineSettings.patternProperties[this.overridePropertyPattern] = patternProperties;
|
||||
windowSettings.patternProperties[this.overridePropertyPattern] = patternProperties;
|
||||
resourceSettings.patternProperties[this.overridePropertyPattern] = patternProperties;
|
||||
|
||||
|
||||
@@ -18,7 +18,6 @@ export interface ParsedArgs {
|
||||
waitMarkerFilePath?: string;
|
||||
diff?: boolean;
|
||||
add?: boolean;
|
||||
gitCredential?: string;
|
||||
goto?: boolean;
|
||||
'new-window'?: boolean;
|
||||
'unity-launch'?: boolean; // Always open a new window, except if opening the first window or opening a file or folder as part of the launch.
|
||||
|
||||
@@ -197,7 +197,7 @@ function wrapText(text: string, columns: number): string[] {
|
||||
return lines;
|
||||
}
|
||||
|
||||
export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true): string {
|
||||
export function buildHelpMessage(productName: string, executableName: string, version: string, isOptionSupported = (_: Option) => true, isPipeSupported = true): string {
|
||||
const columns = (process.stdout).isTTY && (process.stdout).columns || 80;
|
||||
|
||||
let categories = new HelpCategories();
|
||||
|
||||
@@ -86,7 +86,7 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
|
||||
get onDidUninstallExtension(): Event<DidUninstallExtensionEvent> { return this.channel.listen('onDidUninstallExtension'); }
|
||||
|
||||
zip(extension: ILocalExtension): Promise<URI> {
|
||||
return Promise.resolve(this.channel.call('zip', [extension]).then(result => URI.revive(result)));
|
||||
return Promise.resolve(this.channel.call('zip', [extension]).then(result => URI.revive(<UriComponents>result)));
|
||||
}
|
||||
|
||||
unzip(zipLocation: URI, type: ExtensionType): Promise<IExtensionIdentifier> {
|
||||
@@ -122,4 +122,4 @@ export class ExtensionManagementChannelClient implements IExtensionManagementSer
|
||||
getExtensionsReport(): Promise<IReportedExtension[]> {
|
||||
return Promise.resolve(this.channel.call('getExtensionsReport'));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,11 +124,6 @@ export interface IFileService {
|
||||
*/
|
||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||
|
||||
/**
|
||||
* @deprecated use writeFile instead
|
||||
*/
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Updates the content replacing its previous value.
|
||||
*/
|
||||
@@ -148,18 +143,13 @@ export interface IFileService {
|
||||
*/
|
||||
copy(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* @deprecated use createFile2 instead
|
||||
*/
|
||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Creates a new file with the given path and optional contents. The returned promise
|
||||
* will have the stat model object as a result.
|
||||
*
|
||||
* The optional parameter content can be used as value to fill into the new file.
|
||||
*/
|
||||
createFile2(resource: URI, bufferOrReadable?: VSBuffer | VSBufferReadable, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
createFile(resource: URI, bufferOrReadable?: VSBuffer | VSBufferReadable, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
/**
|
||||
* Creates a new folder with the given path. The returned promise
|
||||
@@ -666,6 +656,7 @@ export interface ITextSnapshot {
|
||||
*/
|
||||
export function snapshotToString(snapshot: ITextSnapshot): string {
|
||||
const chunks: string[] = [];
|
||||
|
||||
let chunk: string | null;
|
||||
while (typeof (chunk = snapshot.read()) === 'string') {
|
||||
chunks.push(chunk);
|
||||
@@ -674,6 +665,22 @@ export function snapshotToString(snapshot: ITextSnapshot): string {
|
||||
return chunks.join('');
|
||||
}
|
||||
|
||||
export function stringToSnapshot(value: string): ITextSnapshot {
|
||||
let done = false;
|
||||
|
||||
return {
|
||||
read(): string | null {
|
||||
if (!done) {
|
||||
done = true;
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export class TextSnapshotReadable implements VSBufferReadable {
|
||||
private preambleHandled: boolean;
|
||||
|
||||
@@ -703,6 +710,22 @@ export class TextSnapshotReadable implements VSBufferReadable {
|
||||
}
|
||||
}
|
||||
|
||||
export function toBufferOrReadable(value: string): VSBuffer;
|
||||
export function toBufferOrReadable(value: ITextSnapshot): VSBufferReadable;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot): VSBuffer | VSBufferReadable;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined;
|
||||
export function toBufferOrReadable(value: string | ITextSnapshot | undefined): VSBuffer | VSBufferReadable | undefined {
|
||||
if (typeof value === 'undefined') {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
if (typeof value === 'string') {
|
||||
return VSBuffer.fromString(value);
|
||||
}
|
||||
|
||||
return new TextSnapshotReadable(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Streamable content and meta information of a file.
|
||||
*/
|
||||
@@ -1158,8 +1181,4 @@ export interface ILegacyFileService extends IDisposable {
|
||||
resolveContent(resource: URI, options?: IResolveContentOptions): Promise<IContent>;
|
||||
|
||||
resolveStreamContent(resource: URI, options?: IResolveContentOptions): Promise<IStreamContent>;
|
||||
|
||||
updateContent(resource: URI, value: string | ITextSnapshot, options?: IWriteTextFileOptions): Promise<IFileStatWithMetadata>;
|
||||
|
||||
createFile(resource: URI, content?: string, options?: ICreateFileOptions): Promise<IFileStatWithMetadata>;
|
||||
}
|
||||
@@ -15,7 +15,7 @@ import { isWindows, isMacintosh } from 'vs/base/common/platform';
|
||||
import { IWorkspaceIdentifier, IWorkspacesMainService, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
||||
import { IHistoryMainService, IRecentlyOpened, isRecentWorkspace, isRecentFolder, IRecent, isRecentFile, IRecentFolder, IRecentWorkspace, IRecentFile } from 'vs/platform/history/common/history';
|
||||
import { ThrottledDelayer } from 'vs/base/common/async';
|
||||
import { isEqual as areResourcesEqual, dirname, originalFSPath } from 'vs/base/common/resources';
|
||||
import { isEqual as areResourcesEqual, dirname, originalFSPath, basename } from 'vs/base/common/resources';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
@@ -29,6 +29,12 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
private static readonly MAX_MACOS_DOCK_RECENT_FOLDERS = 10;
|
||||
private static readonly MAX_MACOS_DOCK_RECENT_FILES = 5;
|
||||
|
||||
// Exclude some very common files from the dock/taskbar
|
||||
private static readonly COMMON_FILES_FILTER = [
|
||||
'COMMIT_EDITMSG',
|
||||
'MERGE_MSG'
|
||||
];
|
||||
|
||||
private static readonly recentlyOpenedStorageKey = 'openedPathsList';
|
||||
|
||||
_serviceBrand: any;
|
||||
@@ -52,17 +58,29 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
const files: IRecentFile[] = [];
|
||||
|
||||
for (let curr of newlyAdded) {
|
||||
|
||||
// Workspace
|
||||
if (isRecentWorkspace(curr)) {
|
||||
if (!this.workspacesMainService.isUntitledWorkspace(curr.workspace) && indexOfWorkspace(workspaces, curr.workspace) === -1) {
|
||||
workspaces.push(curr);
|
||||
}
|
||||
} else if (isRecentFolder(curr)) {
|
||||
}
|
||||
|
||||
// Folder
|
||||
else if (isRecentFolder(curr)) {
|
||||
if (indexOfFolder(workspaces, curr.folderUri) === -1) {
|
||||
workspaces.push(curr);
|
||||
}
|
||||
} else {
|
||||
if (indexOfFile(files, curr.fileUri) === -1) {
|
||||
}
|
||||
|
||||
// File
|
||||
else {
|
||||
const alreadyExistsInHistory = indexOfFile(files, curr.fileUri) >= 0;
|
||||
const shouldBeFiltered = curr.fileUri.scheme === Schemas.file && HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(curr.fileUri)) >= 0;
|
||||
|
||||
if (!alreadyExistsInHistory && !shouldBeFiltered) {
|
||||
files.push(curr);
|
||||
|
||||
// Add to recent documents (Windows only, macOS later)
|
||||
if (isWindows && curr.fileUri.scheme === Schemas.file) {
|
||||
app.addRecentDocument(curr.fileUri.fsPath);
|
||||
@@ -76,6 +94,7 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
if (workspaces.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) {
|
||||
workspaces.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES;
|
||||
}
|
||||
|
||||
if (files.length > HistoryMainService.MAX_TOTAL_RECENT_ENTRIES) {
|
||||
files.length = HistoryMainService.MAX_TOTAL_RECENT_ENTRIES;
|
||||
}
|
||||
@@ -143,7 +162,7 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
// Fill in files
|
||||
for (let i = 0, entries = 0; i < mru.files.length && entries < HistoryMainService.MAX_MACOS_DOCK_RECENT_FILES; i++) {
|
||||
const loc = location(mru.files[i]);
|
||||
if (loc.scheme === Schemas.file) {
|
||||
if (loc.scheme === Schemas.file && HistoryMainService.COMMON_FILES_FILTER.indexOf(basename(loc)) === -1) {
|
||||
const filePath = originalFSPath(loc);
|
||||
if (await exists(filePath)) {
|
||||
app.addRecentDocument(filePath);
|
||||
@@ -162,7 +181,6 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
}
|
||||
|
||||
getRecentlyOpened(currentWorkspace?: IWorkspaceIdentifier, currentFolder?: ISingleFolderWorkspaceIdentifier, currentFiles?: IPath[]): IRecentlyOpened {
|
||||
|
||||
const workspaces: Array<IRecentFolder | IRecentWorkspace> = [];
|
||||
const files: IRecentFile[] = [];
|
||||
|
||||
@@ -170,6 +188,7 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
if (currentWorkspace && !this.workspacesMainService.isUntitledWorkspace(currentWorkspace)) {
|
||||
workspaces.push({ workspace: currentWorkspace });
|
||||
}
|
||||
|
||||
if (currentFolder) {
|
||||
workspaces.push({ folderUri: currentFolder });
|
||||
}
|
||||
@@ -183,12 +202,14 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this.addEntriesFromStorage(workspaces, files);
|
||||
|
||||
return { workspaces, files };
|
||||
}
|
||||
|
||||
private addEntriesFromStorage(workspaces: Array<IRecentFolder | IRecentWorkspace>, files: IRecentFile[]) {
|
||||
|
||||
// Get from storage
|
||||
let recents = this.getRecentlyOpenedFromStorage();
|
||||
for (let recent of recents.workspaces) {
|
||||
@@ -199,6 +220,7 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
workspaces.push(recent);
|
||||
}
|
||||
}
|
||||
|
||||
for (let recent of recents.files) {
|
||||
let index = indexOfFile(files, recent.fileUri);
|
||||
if (index >= 0) {
|
||||
@@ -211,11 +233,13 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
|
||||
private getRecentlyOpenedFromStorage(): IRecentlyOpened {
|
||||
const storedRecents = this.stateService.getItem<RecentlyOpenedStorageData>(HistoryMainService.recentlyOpenedStorageKey);
|
||||
|
||||
return restoreRecentlyOpened(storedRecents);
|
||||
}
|
||||
|
||||
private saveRecentlyOpened(recent: IRecentlyOpened): void {
|
||||
const serialized = toStoreData(recent);
|
||||
|
||||
this.stateService.setItem(HistoryMainService.recentlyOpenedStorageKey, serialized);
|
||||
}
|
||||
|
||||
@@ -268,16 +292,17 @@ export class HistoryMainService implements IHistoryMainService {
|
||||
items: arrays.coalesce(this.getRecentlyOpened().workspaces.slice(0, 7 /* limit number of entries here */).map(recent => {
|
||||
const workspace = isRecentWorkspace(recent) ? recent.workspace : recent.folderUri;
|
||||
const title = recent.label || getSimpleWorkspaceLabel(workspace, this.environmentService.untitledWorkspacesHome);
|
||||
|
||||
let description;
|
||||
let args;
|
||||
if (isSingleFolderWorkspaceIdentifier(workspace)) {
|
||||
const parentFolder = dirname(workspace);
|
||||
description = nls.localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(parentFolder, this.environmentService));
|
||||
description = nls.localize('folderDesc', "{0} {1}", getBaseLabel(workspace), getPathLabel(dirname(workspace), this.environmentService));
|
||||
args = `--folder-uri "${workspace.toString()}"`;
|
||||
} else {
|
||||
description = nls.localize('codeWorkspace', "Code Workspace");
|
||||
args = `--file-uri "${workspace.configPath.toString()}"`;
|
||||
}
|
||||
|
||||
return <Electron.JumpListItem>{
|
||||
type: 'task',
|
||||
title,
|
||||
@@ -308,9 +333,11 @@ function location(recent: IRecent): URI {
|
||||
if (isRecentFolder(recent)) {
|
||||
return recent.folderUri;
|
||||
}
|
||||
|
||||
if (isRecentFile(recent)) {
|
||||
return recent.fileUri;
|
||||
}
|
||||
|
||||
return recent.workspace.configPath;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,7 @@ export function restoreRecentlyOpened(data: RecentlyOpenedStorageData | undefine
|
||||
result.workspaces.push({ workspace: { id: workspace['id'], configPath: URI.file(workspace['configPath']) } });
|
||||
} else if (workspace && typeof workspace['path'] === 'string' && typeof workspace['scheme'] === 'string') {
|
||||
// added by 1.26-insiders
|
||||
result.workspaces.push({ folderUri: URI.revive(workspace) });
|
||||
result.workspaces.push({ folderUri: URI.revive(<UriComponents>workspace) });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ export interface IssueReporterData extends WindowData {
|
||||
styles: IssueReporterStyles;
|
||||
enabledExtensions: IssueReporterExtensionData[];
|
||||
issueType?: IssueType;
|
||||
extensionId?: string;
|
||||
}
|
||||
|
||||
export interface ISettingSearchResult {
|
||||
|
||||
@@ -30,7 +30,8 @@ export const enum ProgressLocation {
|
||||
Scm = 3,
|
||||
Extensions = 5,
|
||||
Window = 10,
|
||||
Notification = 15
|
||||
Notification = 15,
|
||||
Dialog = 20
|
||||
}
|
||||
|
||||
export interface IProgressOptions {
|
||||
|
||||
@@ -19,7 +19,6 @@ export interface IRemoteAgentEnvironment {
|
||||
userHome: URI;
|
||||
extensions: IExtensionDescription[];
|
||||
os: OperatingSystem;
|
||||
syncExtensions: boolean;
|
||||
}
|
||||
|
||||
export interface RemoteAgentConnectionContext {
|
||||
|
||||
@@ -22,31 +22,30 @@ export interface IFileChangeDto {
|
||||
|
||||
export class RemoteExtensionsFileSystemProvider extends Disposable implements IFileSystemProvider {
|
||||
|
||||
private readonly _session: string;
|
||||
private readonly _channel: IChannel;
|
||||
private readonly session: string = generateUuid();
|
||||
|
||||
private readonly _onDidChange = this._register(new Emitter<IFileChange[]>());
|
||||
readonly onDidChangeFile: Event<IFileChange[]> = this._onDidChange.event;
|
||||
|
||||
public capabilities: FileSystemProviderCapabilities;
|
||||
private readonly _onDidChangeCapabilities = this._register(new Emitter<void>());
|
||||
readonly onDidChangeCapabilities: Event<void> = this._onDidChangeCapabilities.event;
|
||||
|
||||
constructor(channel: IChannel, environment: Promise<IRemoteAgentEnvironment | null>) {
|
||||
private _capabilities: FileSystemProviderCapabilities;
|
||||
get capabilities(): FileSystemProviderCapabilities { return this._capabilities; }
|
||||
|
||||
constructor(private readonly channel: IChannel, environment: Promise<IRemoteAgentEnvironment | null>) {
|
||||
super();
|
||||
this._session = generateUuid();
|
||||
this._channel = channel;
|
||||
|
||||
this.setCaseSensitive(true);
|
||||
environment.then(remoteAgentEnvironment => this.setCaseSensitive(!!(remoteAgentEnvironment && remoteAgentEnvironment.os === OperatingSystem.Linux)));
|
||||
|
||||
this._channel.listen<IFileChangeDto[]>('filechange', [this._session])((events) => {
|
||||
this._onDidChange.fire(events.map(RemoteExtensionsFileSystemProvider._createFileChange));
|
||||
});
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
super.dispose();
|
||||
private registerListeners(): void {
|
||||
this._register(this.channel.listen<IFileChangeDto[]>('filechange', [this.session])((events) => {
|
||||
this._onDidChange.fire(events.map(event => ({ resource: URI.revive(event.resource), type: event.type })));
|
||||
}));
|
||||
}
|
||||
|
||||
setCaseSensitive(isCaseSensitive: boolean) {
|
||||
@@ -54,58 +53,55 @@ export class RemoteExtensionsFileSystemProvider extends Disposable implements IF
|
||||
FileSystemProviderCapabilities.FileReadWrite
|
||||
| FileSystemProviderCapabilities.FileFolderCopy
|
||||
);
|
||||
|
||||
if (isCaseSensitive) {
|
||||
capabilities |= FileSystemProviderCapabilities.PathCaseSensitive;
|
||||
}
|
||||
this.capabilities = capabilities;
|
||||
|
||||
this._capabilities = capabilities;
|
||||
this._onDidChangeCapabilities.fire(undefined);
|
||||
}
|
||||
|
||||
watch(resource: URI, opts: IWatchOptions): IDisposable {
|
||||
const req = Math.random();
|
||||
this._channel.call('watch', [this._session, req, resource, opts]);
|
||||
return toDisposable(() => {
|
||||
this._channel.call('unwatch', [this._session, req]);
|
||||
});
|
||||
}
|
||||
|
||||
private static _createFileChange(dto: IFileChangeDto): IFileChange {
|
||||
return { resource: URI.revive(dto.resource), type: dto.type };
|
||||
}
|
||||
|
||||
// --- forwarding calls
|
||||
|
||||
stat(resource: URI): Promise<IStat> {
|
||||
return this._channel.call('stat', [resource]);
|
||||
return this.channel.call('stat', [resource]);
|
||||
}
|
||||
|
||||
async readFile(resource: URI): Promise<Uint8Array> {
|
||||
const buff = <VSBuffer>await this._channel.call('readFile', [resource]);
|
||||
const buff = <VSBuffer>await this.channel.call('readFile', [resource]);
|
||||
|
||||
return buff.buffer;
|
||||
}
|
||||
|
||||
writeFile(resource: URI, content: Uint8Array, opts: FileWriteOptions): Promise<void> {
|
||||
const contents = VSBuffer.wrap(content);
|
||||
return this._channel.call('writeFile', [resource, contents, opts]);
|
||||
return this.channel.call('writeFile', [resource, VSBuffer.wrap(content), opts]);
|
||||
}
|
||||
|
||||
delete(resource: URI, opts: FileDeleteOptions): Promise<void> {
|
||||
return this._channel.call('delete', [resource, opts]);
|
||||
return this.channel.call('delete', [resource, opts]);
|
||||
}
|
||||
|
||||
mkdir(resource: URI): Promise<void> {
|
||||
return this._channel.call('mkdir', [resource]);
|
||||
return this.channel.call('mkdir', [resource]);
|
||||
}
|
||||
|
||||
readdir(resource: URI): Promise<[string, FileType][]> {
|
||||
return this._channel.call('readdir', [resource]);
|
||||
return this.channel.call('readdir', [resource]);
|
||||
}
|
||||
|
||||
rename(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._channel.call('rename', [resource, target, opts]);
|
||||
return this.channel.call('rename', [resource, target, opts]);
|
||||
}
|
||||
|
||||
copy(resource: URI, target: URI, opts: FileOverwriteOptions): Promise<void> {
|
||||
return this._channel.call('copy', [resource, target, opts]);
|
||||
return this.channel.call('copy', [resource, target, opts]);
|
||||
}
|
||||
|
||||
watch(resource: URI, opts: IWatchOptions): IDisposable {
|
||||
const req = Math.random();
|
||||
this.channel.call('watch', [this.session, req, resource, opts]);
|
||||
|
||||
return toDisposable(() => this.channel.call('unwatch', [this.session, req]));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,69 +3,12 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { binarySearch } from 'vs/base/common/arrays';
|
||||
import { toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { globals } from 'vs/base/common/platform';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import * as Errors from 'vs/base/common/errors';
|
||||
import { safeStringify } from 'vs/base/common/objects';
|
||||
import BaseErrorTelemetry, { ErrorEvent } from '../common/errorTelemetry';
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"ErrorEvent" : {
|
||||
"stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
interface ErrorEvent {
|
||||
callstack: string;
|
||||
msg?: string;
|
||||
file?: string;
|
||||
line?: number;
|
||||
column?: number;
|
||||
uncaught_error_name?: string;
|
||||
uncaught_error_msg?: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
namespace ErrorEvent {
|
||||
export function compare(a: ErrorEvent, b: ErrorEvent) {
|
||||
if (a.callstack < b.callstack) {
|
||||
return -1;
|
||||
} else if (a.callstack > b.callstack) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default class ErrorTelemetry {
|
||||
|
||||
public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000;
|
||||
|
||||
private _telemetryService: ITelemetryService;
|
||||
private _flushDelay: number;
|
||||
private _flushHandle: any = -1;
|
||||
private _buffer: ErrorEvent[] = [];
|
||||
private _disposables: IDisposable[] = [];
|
||||
|
||||
constructor(telemetryService: ITelemetryService, flushDelay = ErrorTelemetry.ERROR_FLUSH_TIMEOUT) {
|
||||
this._telemetryService = telemetryService;
|
||||
this._flushDelay = flushDelay;
|
||||
|
||||
// (1) check for unexpected but handled errors
|
||||
const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err));
|
||||
this._disposables.push(toDisposable(unbind));
|
||||
|
||||
// (2) check for uncaught global errors
|
||||
export default class ErrorTelemetry extends BaseErrorTelemetry {
|
||||
protected installErrorListeners(): void {
|
||||
let oldOnError: Function;
|
||||
let that = this;
|
||||
if (typeof globals.onerror === 'function') {
|
||||
@@ -84,37 +27,7 @@ export default class ErrorTelemetry {
|
||||
}));
|
||||
}
|
||||
|
||||
dispose() {
|
||||
clearTimeout(this._flushHandle);
|
||||
this._flushBuffer();
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
private _onErrorEvent(err: any): void {
|
||||
|
||||
if (!err) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unwrap nested errors from loader
|
||||
if (err.detail && err.detail.stack) {
|
||||
err = err.detail;
|
||||
}
|
||||
|
||||
// work around behavior in workerServer.ts that breaks up Error.stack
|
||||
let callstack = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack;
|
||||
let msg = err.message ? err.message : safeStringify(err);
|
||||
|
||||
// errors without a stack are not useful telemetry
|
||||
if (!callstack) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enqueue({ msg, callstack });
|
||||
}
|
||||
|
||||
private _onUncaughtError(msg: string, file: string, line: number, column?: number, err?: any): void {
|
||||
|
||||
let data: ErrorEvent = {
|
||||
callstack: msg,
|
||||
msg,
|
||||
@@ -138,38 +51,4 @@ export default class ErrorTelemetry {
|
||||
|
||||
this._enqueue(data);
|
||||
}
|
||||
|
||||
private _enqueue(e: ErrorEvent): void {
|
||||
|
||||
const idx = binarySearch(this._buffer, e, ErrorEvent.compare);
|
||||
if (idx < 0) {
|
||||
e.count = 1;
|
||||
this._buffer.splice(~idx, 0, e);
|
||||
} else {
|
||||
if (!this._buffer[idx].count) {
|
||||
this._buffer[idx].count = 0;
|
||||
}
|
||||
this._buffer[idx].count! += 1;
|
||||
}
|
||||
|
||||
if (this._flushHandle === -1) {
|
||||
this._flushHandle = setTimeout(() => {
|
||||
this._flushBuffer();
|
||||
this._flushHandle = -1;
|
||||
}, this._flushDelay);
|
||||
}
|
||||
}
|
||||
|
||||
private _flushBuffer(): void {
|
||||
for (let error of this._buffer) {
|
||||
/* __GDPR__
|
||||
"UnhandledError" : {
|
||||
"${include}": [ "${ErrorEvent}" ]
|
||||
}
|
||||
*/
|
||||
// {{SQL CARBON EDIT}}
|
||||
//this._telemetryService.publicLog('UnhandledError', error, true);
|
||||
}
|
||||
this._buffer.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
137
src/vs/platform/telemetry/common/errorTelemetry.ts
Normal file
137
src/vs/platform/telemetry/common/errorTelemetry.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { binarySearch } from 'vs/base/common/arrays';
|
||||
import * as Errors from 'vs/base/common/errors';
|
||||
import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||
import { safeStringify } from 'vs/base/common/objects';
|
||||
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||
|
||||
/* __GDPR__FRAGMENT__
|
||||
"ErrorEvent" : {
|
||||
"stack": { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"message" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"filename" : { "classification": "CustomerContent", "purpose": "PerformanceAndHealth" },
|
||||
"callstack": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"msg" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"file" : { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"line": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"column": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true },
|
||||
"uncaught_error_name": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"uncaught_error_msg": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth" },
|
||||
"count": { "classification": "CallstackOrException", "purpose": "PerformanceAndHealth", "isMeasurement": true }
|
||||
}
|
||||
*/
|
||||
export interface ErrorEvent {
|
||||
callstack: string;
|
||||
msg?: string;
|
||||
file?: string;
|
||||
line?: number;
|
||||
column?: number;
|
||||
uncaught_error_name?: string;
|
||||
uncaught_error_msg?: string;
|
||||
count?: number;
|
||||
}
|
||||
|
||||
export namespace ErrorEvent {
|
||||
export function compare(a: ErrorEvent, b: ErrorEvent) {
|
||||
if (a.callstack < b.callstack) {
|
||||
return -1;
|
||||
} else if (a.callstack > b.callstack) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
export default abstract class BaseErrorTelemetry {
|
||||
|
||||
public static ERROR_FLUSH_TIMEOUT: number = 5 * 1000;
|
||||
|
||||
private _telemetryService: ITelemetryService;
|
||||
private _flushDelay: number;
|
||||
private _flushHandle: any = -1;
|
||||
private _buffer: ErrorEvent[] = [];
|
||||
protected _disposables: IDisposable[] = [];
|
||||
|
||||
constructor(telemetryService: ITelemetryService, flushDelay = BaseErrorTelemetry.ERROR_FLUSH_TIMEOUT) {
|
||||
this._telemetryService = telemetryService;
|
||||
this._flushDelay = flushDelay;
|
||||
|
||||
// (1) check for unexpected but handled errors
|
||||
const unbind = Errors.errorHandler.addListener((err) => this._onErrorEvent(err));
|
||||
this._disposables.push(toDisposable(unbind));
|
||||
|
||||
// (2) install implementation-specific error listeners
|
||||
this.installErrorListeners();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
clearTimeout(this._flushHandle);
|
||||
this._flushBuffer();
|
||||
this._disposables = dispose(this._disposables);
|
||||
}
|
||||
|
||||
protected installErrorListeners(): void {
|
||||
// to override
|
||||
}
|
||||
|
||||
private _onErrorEvent(err: any): void {
|
||||
|
||||
if (!err) {
|
||||
return;
|
||||
}
|
||||
|
||||
// unwrap nested errors from loader
|
||||
if (err.detail && err.detail.stack) {
|
||||
err = err.detail;
|
||||
}
|
||||
|
||||
// work around behavior in workerServer.ts that breaks up Error.stack
|
||||
let callstack = Array.isArray(err.stack) ? err.stack.join('\n') : err.stack;
|
||||
let msg = err.message ? err.message : safeStringify(err);
|
||||
|
||||
// errors without a stack are not useful telemetry
|
||||
if (!callstack) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._enqueue({ msg, callstack });
|
||||
}
|
||||
|
||||
protected _enqueue(e: ErrorEvent): void {
|
||||
|
||||
const idx = binarySearch(this._buffer, e, ErrorEvent.compare);
|
||||
if (idx < 0) {
|
||||
e.count = 1;
|
||||
this._buffer.splice(~idx, 0, e);
|
||||
} else {
|
||||
if (!this._buffer[idx].count) {
|
||||
this._buffer[idx].count = 0;
|
||||
}
|
||||
this._buffer[idx].count! += 1;
|
||||
}
|
||||
|
||||
if (this._flushHandle === -1) {
|
||||
this._flushHandle = setTimeout(() => {
|
||||
this._flushBuffer();
|
||||
this._flushHandle = -1;
|
||||
}, this._flushDelay);
|
||||
}
|
||||
}
|
||||
|
||||
private _flushBuffer(): void {
|
||||
for (let error of this._buffer) {
|
||||
/* __GDPR__
|
||||
"UnhandledError" : {
|
||||
"${include}": [ "${ErrorEvent}" ]
|
||||
}
|
||||
*/
|
||||
// {{SQL CARBON EDIT}}
|
||||
// this._telemetryService.publicLog('UnhandledError', error, true);
|
||||
}
|
||||
this._buffer.length = 0;
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,8 @@ export interface ITelemetryService {
|
||||
*/
|
||||
publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<void>;
|
||||
|
||||
setEnabled(value: boolean): void;
|
||||
|
||||
getTelemetryInfo(): Promise<ITelemetryInfo>;
|
||||
|
||||
isOptedIn: boolean;
|
||||
|
||||
@@ -31,6 +31,7 @@ export class TelemetryService implements ITelemetryService {
|
||||
private _commonProperties: Promise<{ [name: string]: any; }>;
|
||||
private _piiPaths: string[];
|
||||
private _userOptIn: boolean;
|
||||
private _enabled: boolean;
|
||||
|
||||
private _disposables: IDisposable[] = [];
|
||||
private _cleanupPatterns: RegExp[] = [];
|
||||
@@ -43,6 +44,7 @@ export class TelemetryService implements ITelemetryService {
|
||||
this._commonProperties = config.commonProperties || Promise.resolve({});
|
||||
this._piiPaths = config.piiPaths || [];
|
||||
this._userOptIn = true;
|
||||
this._enabled = true;
|
||||
|
||||
// static cleanup pattern for: `file:///DANGEROUS/PATH/resources/app/Useful/Information`
|
||||
this._cleanupPatterns = [/file:\/\/\/.*?\/resources\/app\//gi];
|
||||
@@ -74,13 +76,17 @@ export class TelemetryService implements ITelemetryService {
|
||||
}
|
||||
}
|
||||
|
||||
setEnabled(value: boolean): void {
|
||||
this._enabled = value;
|
||||
}
|
||||
|
||||
private _updateUserOptIn(): void {
|
||||
const config = this._configurationService.getValue<any>(TELEMETRY_SECTION_ID);
|
||||
this._userOptIn = config ? config.enableTelemetry : this._userOptIn;
|
||||
}
|
||||
|
||||
get isOptedIn(): boolean {
|
||||
return this._userOptIn;
|
||||
return this._userOptIn && this._enabled;
|
||||
}
|
||||
|
||||
getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||
@@ -100,7 +106,7 @@ export class TelemetryService implements ITelemetryService {
|
||||
|
||||
publicLog(eventName: string, data?: ITelemetryData, anonymizeFilePaths?: boolean): Promise<any> {
|
||||
// don't send events when the user is optout
|
||||
if (!this._userOptIn) {
|
||||
if (!this.isOptedIn) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ export const NullTelemetryService = new class implements ITelemetryService {
|
||||
publicLog(eventName: string, data?: ITelemetryData) {
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
setEnabled() { }
|
||||
isOptedIn: true;
|
||||
getTelemetryInfo(): Promise<ITelemetryInfo> {
|
||||
return Promise.resolve({
|
||||
|
||||
44
src/vs/platform/telemetry/node/errorTelemetry.ts
Normal file
44
src/vs/platform/telemetry/node/errorTelemetry.ts
Normal file
@@ -0,0 +1,44 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { onUnexpectedError } from 'vs/base/common/errors';
|
||||
import BaseErrorTelemetry from '../common/errorTelemetry';
|
||||
|
||||
export default class ErrorTelemetry extends BaseErrorTelemetry {
|
||||
protected installErrorListeners(): void {
|
||||
// Print a console message when rejection isn't handled within N seconds. For details:
|
||||
// see https://nodejs.org/api/process.html#process_event_unhandledrejection
|
||||
// and https://nodejs.org/api/process.html#process_event_rejectionhandled
|
||||
const unhandledPromises: Promise<any>[] = [];
|
||||
process.on('unhandledRejection', (reason: any, promise: Promise<any>) => {
|
||||
unhandledPromises.push(promise);
|
||||
setTimeout(() => {
|
||||
const idx = unhandledPromises.indexOf(promise);
|
||||
if (idx >= 0) {
|
||||
promise.catch(e => {
|
||||
unhandledPromises.splice(idx, 1);
|
||||
console.warn(`rejected promise not handled within 1 second: ${e}`);
|
||||
if (e.stack) {
|
||||
console.warn(`stack trace: ${e.stack}`);
|
||||
}
|
||||
onUnexpectedError(reason);
|
||||
});
|
||||
}
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
process.on('rejectionHandled', (promise: Promise<any>) => {
|
||||
const idx = unhandledPromises.indexOf(promise);
|
||||
if (idx >= 0) {
|
||||
unhandledPromises.splice(idx, 1);
|
||||
}
|
||||
});
|
||||
|
||||
// Print a console message when an exception isn't handled.
|
||||
process.on('uncaughtException', (err: Error) => {
|
||||
onUnexpectedError(err);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@ import * as json from 'vs/base/common/json';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { normalizeDriveLetter } from 'vs/base/common/labels';
|
||||
import { toSlashes } from 'vs/base/common/extpath';
|
||||
import { FormattingOptions } from 'vs/base/common/jsonFormatter';
|
||||
import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts';
|
||||
|
||||
export const IWorkspacesMainService = createDecorator<IWorkspacesMainService>('workspacesMainService');
|
||||
export const IWorkspacesService = createDecorator<IWorkspacesService>('workspacesService');
|
||||
@@ -75,6 +77,7 @@ export interface IResolvedWorkspace extends IWorkspaceIdentifier {
|
||||
|
||||
export interface IStoredWorkspace {
|
||||
folders: IStoredWorkspaceFolder[];
|
||||
remoteAuthority?: string;
|
||||
}
|
||||
|
||||
export interface IWorkspaceSavedEvent {
|
||||
@@ -232,12 +235,15 @@ export function rewriteWorkspaceFileForNewLocation(rawWorkspaceContents: string,
|
||||
|
||||
// Preserve as much of the existing workspace as possible by using jsonEdit
|
||||
// and only changing the folders portion.
|
||||
let newRawWorkspaceContents = rawWorkspaceContents;
|
||||
const edits = jsonEdit.setProperty(rawWorkspaceContents, ['folders'], rewrittenFolders, { insertSpaces: false, tabSize: 4, eol: (isLinux || isMacintosh) ? '\n' : '\r\n' });
|
||||
edits.forEach(edit => {
|
||||
newRawWorkspaceContents = jsonEdit.applyEdit(rawWorkspaceContents, edit);
|
||||
});
|
||||
return newRawWorkspaceContents;
|
||||
const formattingOptions: FormattingOptions = { insertSpaces: false, tabSize: 4, eol: (isLinux || isMacintosh) ? '\n' : '\r\n' };
|
||||
const edits = jsonEdit.setProperty(rawWorkspaceContents, ['folders'], rewrittenFolders, formattingOptions);
|
||||
let newContent = jsonEdit.applyEdits(rawWorkspaceContents, edits);
|
||||
|
||||
if (storedWorkspace.remoteAuthority === getRemoteAuthority(targetConfigPathURI)) {
|
||||
// unsaved remote workspaces have the remoteAuthority set. Remove it when no longer nexessary.
|
||||
newContent = jsonEdit.applyEdits(newContent, jsonEdit.removeProperty(newContent, ['remoteAuthority'], formattingOptions));
|
||||
}
|
||||
return newContent;
|
||||
}
|
||||
|
||||
function doParseStoredWorkspace(path: URI, contents: string): IStoredWorkspace {
|
||||
|
||||
5
src/vs/vscode.d.ts
vendored
5
src/vs/vscode.d.ts
vendored
@@ -5973,6 +5973,11 @@ declare module 'vscode' {
|
||||
*/
|
||||
export const appRoot: string;
|
||||
|
||||
/**
|
||||
* The custom uri scheme the editor registers to in the operating system.
|
||||
*/
|
||||
export const uriScheme: string;
|
||||
|
||||
/**
|
||||
* Represents the preferred user-language, like `de-CH`, `fr`, or `en-US`.
|
||||
*/
|
||||
|
||||
5
src/vs/vscode.proposed.d.ts
vendored
5
src/vs/vscode.proposed.d.ts
vendored
@@ -616,11 +616,6 @@ declare module 'vscode' {
|
||||
* An [event](#Event) that fires when the log level has changed.
|
||||
*/
|
||||
export const onDidChangeLogLevel: Event<LogLevel>;
|
||||
|
||||
/**
|
||||
* The custom uri scheme the editor registers to in the operating system, like 'vscode', 'vscode-insiders'.
|
||||
*/
|
||||
export const uriScheme: string;
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
@@ -112,7 +112,7 @@ export class MainThreadDecorations implements MainThreadDecorationsShape {
|
||||
const provider = this._provider.get(handle);
|
||||
if (provider) {
|
||||
const [emitter] = provider;
|
||||
emitter.fire(resources && resources.map(URI.revive));
|
||||
emitter.fire(resources && resources.map(r => URI.revive(r)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -162,7 +162,7 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
|
||||
});
|
||||
} else {
|
||||
searchOp.addMatch({
|
||||
resource: URI.revive(result)
|
||||
resource: URI.revive(<UriComponents>result)
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -47,7 +47,7 @@ export class OpenFolderAPICommand {
|
||||
arg = { forceNewWindow: arg };
|
||||
}
|
||||
if (!uri) {
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', arg.forceNewWindow);
|
||||
return executor.executeCommand('_files.pickFolderAndOpen', { forceNewWindow: arg.forceNewWindow });
|
||||
}
|
||||
const options: IOpenSettings = { forceNewWindow: arg.forceNewWindow, noRecentEntry: arg.noRecentEntry };
|
||||
uri = URI.revive(uri);
|
||||
@@ -144,6 +144,13 @@ export class RemoveFromRecentlyOpenedAPICommand {
|
||||
}
|
||||
CommandsRegistry.registerCommand(RemoveFromRecentlyOpenedAPICommand.ID, adjustHandler(RemoveFromRecentlyOpenedAPICommand.execute));
|
||||
|
||||
export class OpenIssueReporter {
|
||||
public static ID = 'vscode.openIssueReporter';
|
||||
public static execute(executor: ICommandsExecutor, extensionId: string): Promise<void> {
|
||||
return executor.executeCommand('workbench.action.openIssueReporter', [extensionId]);
|
||||
}
|
||||
}
|
||||
|
||||
interface RecentEntry {
|
||||
uri: URI;
|
||||
type: 'workspace' | 'folder' | 'file';
|
||||
|
||||
@@ -35,16 +35,17 @@ const configurationEntrySchema: IJSONSchema = {
|
||||
properties: {
|
||||
isExecutable: {
|
||||
type: 'boolean',
|
||||
deprecationMessage: 'This property is deprecated. Instead use `scope` property and set it to `application` value.'
|
||||
deprecationMessage: 'This property is deprecated. Instead use `scope` property and set it to `machine` value.'
|
||||
},
|
||||
scope: {
|
||||
type: 'string',
|
||||
enum: ['application', 'window', 'resource'],
|
||||
enum: ['application', 'machine', 'window', 'resource'],
|
||||
default: 'window',
|
||||
enumDescriptions: [
|
||||
nls.localize('scope.application.description', "Application specific configuration, which can be configured only in User settings."),
|
||||
nls.localize('scope.window.description', "Window specific configuration, which can be configured in the User or Workspace settings."),
|
||||
nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the User, Workspace or Folder settings.")
|
||||
nls.localize('scope.application.description', "Application specific configuration, which can be configured only in local user settings."),
|
||||
nls.localize('scope.machine.description', "Machine specific configuration, which can be configured only in local and remote user settings."),
|
||||
nls.localize('scope.window.description', "Window specific configuration, which can be configured in the user or workspace settings."),
|
||||
nls.localize('scope.resource.description', "Resource specific configuration, which can be configured in the user, workspace or folder settings.")
|
||||
],
|
||||
description: nls.localize('scope.description', "Scope in which the configuration is applicable. Available scopes are `window` and `resource`.")
|
||||
},
|
||||
@@ -161,7 +162,7 @@ configurationExtPoint.setHandler((extensions, { added, removed }) => {
|
||||
validateProperties(configuration, extension);
|
||||
|
||||
configuration.id = node.id || extension.description.identifier.value;
|
||||
configuration.contributedByExtension = true;
|
||||
configuration.extensionInfo = { id: extension.description.identifier.value };
|
||||
configuration.title = configuration.title || extension.description.displayName || extension.description.identifier.value;
|
||||
configurations.push(configuration);
|
||||
return configurations;
|
||||
@@ -210,6 +211,8 @@ function validateProperties(configuration: IConfigurationNode, extension: IExten
|
||||
if (propertyConfiguration.scope) {
|
||||
if (propertyConfiguration.scope.toString() === 'application') {
|
||||
propertyConfiguration.scope = ConfigurationScope.APPLICATION;
|
||||
} else if (propertyConfiguration.scope.toString() === 'machine') {
|
||||
propertyConfiguration.scope = ConfigurationScope.MACHINE;
|
||||
} else if (propertyConfiguration.scope.toString() === 'resource') {
|
||||
propertyConfiguration.scope = ConfigurationScope.RESOURCE;
|
||||
} else {
|
||||
|
||||
@@ -15,7 +15,7 @@ import * as search from 'vs/workbench/contrib/search/common/search';
|
||||
import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { CustomCodeAction } from 'vs/workbench/api/common/extHostLanguageFeatures';
|
||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand } from './apiCommands';
|
||||
import { ICommandsExecutor, OpenFolderAPICommand, DiffAPICommand, OpenAPICommand, RemoveFromRecentlyOpenedAPICommand, SetEditorLayoutAPICommand, OpenIssueReporter } from './apiCommands';
|
||||
import { EditorGroupLayout } from 'vs/workbench/services/editor/common/editorGroupsService';
|
||||
import { isFalsyOrEmpty } from 'vs/base/common/arrays';
|
||||
|
||||
@@ -258,6 +258,13 @@ export class ExtHostApiCommands {
|
||||
{ name: 'layout', description: 'The editor layout to set.', constraint: (value: EditorGroupLayout) => typeof value === 'object' && Array.isArray(value.groups) }
|
||||
]
|
||||
});
|
||||
|
||||
this._register(OpenIssueReporter.ID, adjustHandler(OpenIssueReporter.execute), {
|
||||
description: 'Opens the issue reporter with the provided extension id as the selected source',
|
||||
args: [
|
||||
{ name: 'extensionId', description: 'extensionId to report an issue on', constraint: (value: any) => typeof value === 'string' }
|
||||
]
|
||||
});
|
||||
}
|
||||
|
||||
// --- command impl
|
||||
|
||||
@@ -17,7 +17,7 @@ export class ExtHostDialogs {
|
||||
|
||||
showOpenDialog(options: vscode.OpenDialogOptions): Promise<URI[] | undefined> {
|
||||
return this._proxy.$showOpenDialog(options).then(filepaths => {
|
||||
return filepaths ? filepaths.map(URI.revive) : undefined;
|
||||
return filepaths ? filepaths.map(p => URI.revive(p)) : undefined;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
59
src/vs/workbench/api/common/extHostMemento.ts
Normal file
59
src/vs/workbench/api/common/extHostMemento.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionMemento } from 'vs/workbench/api/common/extHostExtensionActivator';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
|
||||
export class ExtensionMemento implements IExtensionMemento {
|
||||
|
||||
private readonly _id: string;
|
||||
private readonly _shared: boolean;
|
||||
private readonly _storage: ExtHostStorage;
|
||||
|
||||
private readonly _init: Promise<ExtensionMemento>;
|
||||
private _value: { [n: string]: any; };
|
||||
private readonly _storageListener: IDisposable;
|
||||
|
||||
constructor(id: string, global: boolean, storage: ExtHostStorage) {
|
||||
this._id = id;
|
||||
this._shared = global;
|
||||
this._storage = storage;
|
||||
|
||||
this._init = this._storage.getValue(this._shared, this._id, Object.create(null)).then(value => {
|
||||
this._value = value;
|
||||
return this;
|
||||
});
|
||||
|
||||
this._storageListener = this._storage.onDidChangeStorage(e => {
|
||||
if (e.shared === this._shared && e.key === this._id) {
|
||||
this._value = e.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
get whenReady(): Promise<ExtensionMemento> {
|
||||
return this._init;
|
||||
}
|
||||
|
||||
get<T>(key: string, defaultValue: T): T {
|
||||
let value = this._value[key];
|
||||
if (typeof value === 'undefined') {
|
||||
value = defaultValue;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
update(key: string, value: any): Promise<boolean> {
|
||||
this._value[key] = value;
|
||||
return this._storage
|
||||
.setValue(this._shared, this._id, this._value)
|
||||
.then(() => true);
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._storageListener.dispose();
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,7 @@ import * as vscode from 'vscode';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
|
||||
export abstract class AbstractExtHostOutputChannel extends Disposable implements vscode.OutputChannel {
|
||||
|
||||
@@ -35,7 +36,7 @@ export abstract class AbstractExtHostOutputChannel extends Disposable implements
|
||||
|
||||
append(value: string): void {
|
||||
this.validate();
|
||||
this._offset += value ? Buffer.from(value).byteLength : 0;
|
||||
this._offset += value ? VSBuffer.fromString(value).byteLength : 0;
|
||||
}
|
||||
|
||||
update(): void {
|
||||
|
||||
@@ -478,8 +478,8 @@ export namespace WorkspaceEdit {
|
||||
);
|
||||
} else {
|
||||
result.renameFile(
|
||||
URI.revive((<ResourceFileEditDto>edit).oldUri),
|
||||
URI.revive((<ResourceFileEditDto>edit).newUri),
|
||||
URI.revive((<ResourceFileEditDto>edit).oldUri!),
|
||||
URI.revive((<ResourceFileEditDto>edit).newUri!),
|
||||
(<ResourceFileEditDto>edit).options
|
||||
);
|
||||
}
|
||||
|
||||
@@ -420,7 +420,7 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac
|
||||
}
|
||||
|
||||
return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token)
|
||||
.then(data => Array.isArray(data) ? data.map(URI.revive) : []);
|
||||
.then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []);
|
||||
}
|
||||
|
||||
findTextInFiles(query: vscode.TextSearchQuery, options: vscode.FindTextInFilesOptions, callback: (result: vscode.TextSearchResult) => void, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise<vscode.TextSearchComplete | undefined> {
|
||||
|
||||
@@ -414,7 +414,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews
|
||||
function reviveWebviewOptions(options: WebviewInputOptions): WebviewInputOptions {
|
||||
return {
|
||||
...options,
|
||||
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(URI.revive) : undefined,
|
||||
localResourceRoots: Array.isArray(options.localResourceRoots) ? options.localResourceRoots.map(r => URI.revive(r)) : undefined,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,9 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { localize } from 'vs/nls';
|
||||
import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
import * as errors from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { TernarySearchTree } from 'vs/base/common/map';
|
||||
import * as path from 'vs/base/common/path';
|
||||
import Severity from 'vs/base/common/severity';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
@@ -16,7 +14,7 @@ import { OverviewRulerLane } from 'vs/editor/common/model';
|
||||
import * as languageConfiguration from 'vs/editor/common/modes/languageConfiguration';
|
||||
import { score } from 'vs/editor/common/modes/languageSelector';
|
||||
import * as files from 'vs/platform/files/common/files';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext, MainThreadKeytarShape, IEnvironment, MainThreadWindowShape, MainThreadTelemetryShape } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostContext, IInitData, IMainContext, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostApiCommands } from 'vs/workbench/api/common/extHostApiCommands';
|
||||
import { ExtHostClipboard } from 'vs/workbench/api/common/extHostClipboard';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
@@ -47,7 +45,7 @@ import { LogOutputChannelFactory } from 'vs/workbench/api/node/extHostOutputServ
|
||||
import { ExtHostProgress } from 'vs/workbench/api/common/extHostProgress';
|
||||
import { ExtHostQuickOpen } from 'vs/workbench/api/common/extHostQuickOpen';
|
||||
import { ExtHostSCM } from 'vs/workbench/api/common/extHostSCM';
|
||||
import { ExtHostSearch } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtHostSearch, registerEHSearchProviders } from 'vs/workbench/api/node/extHostSearch';
|
||||
import { ExtHostStatusBar } from 'vs/workbench/api/common/extHostStatusBar';
|
||||
import { ExtHostStorage } from 'vs/workbench/api/common/extHostStorage';
|
||||
import { ExtHostTask } from 'vs/workbench/api/node/extHostTask';
|
||||
@@ -60,7 +58,7 @@ import { ExtHostUrls } from 'vs/workbench/api/common/extHostUrls';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
|
||||
import { ExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { throwProposedApiError, checkProposedApiEnabled, nullExtensionDescription } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { throwProposedApiError, checkProposedApiEnabled } from 'vs/workbench/services/extensions/common/extensions';
|
||||
import { ProxyIdentifier } from 'vs/workbench/services/extensions/common/proxyIdentifier';
|
||||
import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry';
|
||||
import * as vscode from 'vscode';
|
||||
@@ -69,7 +67,7 @@ import { originalFSPath } from 'vs/base/common/resources';
|
||||
import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer';
|
||||
import { withNullAsUndefined } from 'vs/base/common/types';
|
||||
import { values } from 'vs/base/common/collections';
|
||||
import { endsWith } from 'vs/base/common/strings';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -93,11 +91,11 @@ export function createApiFactory(
|
||||
extHostConfiguration: ExtHostConfiguration,
|
||||
extensionService: ExtHostExtensionService,
|
||||
extHostLogService: ExtHostLogService,
|
||||
extHostStorage: ExtHostStorage
|
||||
extHostStorage: ExtHostStorage,
|
||||
schemeTransformer: ISchemeTransformer | null,
|
||||
outputChannelName: string
|
||||
): IExtensionApiFactory {
|
||||
|
||||
const schemeTransformer: ISchemeTransformer | null = null;
|
||||
|
||||
// Addressable instances
|
||||
rpcProtocol.set(ExtHostContext.ExtHostLogService, extHostLogService);
|
||||
const extHostHeapService = rpcProtocol.set(ExtHostContext.ExtHostHeapService, new ExtHostHeapService());
|
||||
@@ -131,6 +129,14 @@ export function createApiFactory(
|
||||
const extHostOutputService = rpcProtocol.set(ExtHostContext.ExtHostOutputService, new ExtHostOutputService(LogOutputChannelFactory, initData.logsLocation, rpcProtocol));
|
||||
rpcProtocol.set(ExtHostContext.ExtHostStorage, extHostStorage);
|
||||
if (initData.remoteAuthority) {
|
||||
extHostTask.registerTaskSystem(Schemas.vscodeRemote, {
|
||||
scheme: Schemas.vscodeRemote,
|
||||
authority: initData.remoteAuthority,
|
||||
platform: process.platform
|
||||
});
|
||||
|
||||
registerEHSearchProviders(extHostSearch, extHostLogService);
|
||||
|
||||
const cliServer = new CLIServer(extHostCommands);
|
||||
process.env['VSCODE_IPC_HOOK_CLI'] = cliServer.ipcHandlePath;
|
||||
}
|
||||
@@ -147,8 +153,7 @@ export function createApiFactory(
|
||||
const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments);
|
||||
|
||||
// Register an output channel for exthost log
|
||||
const name = localize('extensionsLog', "Extension Host");
|
||||
extHostOutputService.createOutputChannelFromLogFile(name, extHostLogService.logFile);
|
||||
extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile);
|
||||
|
||||
// Register API-ish commands
|
||||
ExtHostApiCommands.register(extHostCommands);
|
||||
@@ -881,240 +886,3 @@ class Extension<T> implements vscode.Extension<T> {
|
||||
return this._extensionService.activateByIdWithErrors(this._identifier, new ExtensionActivatedByAPI(false)).then(() => this.exports);
|
||||
}
|
||||
}
|
||||
|
||||
interface LoadFunction {
|
||||
(request: string, parent: { filename: string; }, isMain: any): any;
|
||||
}
|
||||
|
||||
interface INodeModuleFactory {
|
||||
readonly nodeModuleName: string | string[];
|
||||
load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any;
|
||||
alternaiveModuleName?(name: string): string | undefined;
|
||||
}
|
||||
|
||||
export class NodeModuleRequireInterceptor {
|
||||
public static INSTANCE = new NodeModuleRequireInterceptor();
|
||||
|
||||
private readonly _factories: Map<string, INodeModuleFactory>;
|
||||
private readonly _alternatives: ((moduleName: string) => string | undefined)[];
|
||||
|
||||
constructor() {
|
||||
this._factories = new Map<string, INodeModuleFactory>();
|
||||
this._alternatives = [];
|
||||
this._installInterceptor(this._factories, this._alternatives);
|
||||
}
|
||||
|
||||
private _installInterceptor(factories: Map<string, INodeModuleFactory>, alternatives: ((moduleName: string) => string | undefined)[]): void {
|
||||
const node_module = <any>require.__$__nodeRequire('module');
|
||||
const original = node_module._load;
|
||||
node_module._load = function load(request: string, parent: { filename: string; }, isMain: any) {
|
||||
for (let alternativeModuleName of alternatives) {
|
||||
let alternative = alternativeModuleName(request);
|
||||
if (alternative) {
|
||||
request = alternative;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!factories.has(request)) {
|
||||
return original.apply(this, arguments);
|
||||
}
|
||||
return factories.get(request)!.load(request, parent, isMain, original);
|
||||
};
|
||||
}
|
||||
|
||||
public register(interceptor: INodeModuleFactory): void {
|
||||
if (Array.isArray(interceptor.nodeModuleName)) {
|
||||
for (let moduleName of interceptor.nodeModuleName) {
|
||||
this._factories.set(moduleName, interceptor);
|
||||
}
|
||||
} else {
|
||||
this._factories.set(interceptor.nodeModuleName, interceptor);
|
||||
}
|
||||
if (typeof interceptor.alternaiveModuleName === 'function') {
|
||||
this._alternatives.push((moduleName) => {
|
||||
return interceptor.alternaiveModuleName!(moduleName);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class VSCodeNodeModuleFactory implements INodeModuleFactory {
|
||||
public readonly nodeModuleName = 'vscode';
|
||||
|
||||
private readonly _extApiImpl = new Map<string, typeof vscode>();
|
||||
private _defaultApiImpl: typeof vscode;
|
||||
|
||||
constructor(
|
||||
private readonly _apiFactory: IExtensionApiFactory,
|
||||
private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>,
|
||||
private readonly _extensionRegistry: ExtensionDescriptionRegistry,
|
||||
private readonly _configProvider: ExtHostConfigProvider
|
||||
) {
|
||||
}
|
||||
|
||||
public load(request: string, parent: { filename: string; }): any {
|
||||
|
||||
// get extension id from filename and api for extension
|
||||
const ext = this._extensionPaths.findSubstr(URI.file(parent.filename).fsPath);
|
||||
if (ext) {
|
||||
let apiImpl = this._extApiImpl.get(ExtensionIdentifier.toKey(ext.identifier));
|
||||
if (!apiImpl) {
|
||||
apiImpl = this._apiFactory(ext, this._extensionRegistry, this._configProvider);
|
||||
this._extApiImpl.set(ExtensionIdentifier.toKey(ext.identifier), apiImpl);
|
||||
}
|
||||
return apiImpl;
|
||||
}
|
||||
|
||||
// fall back to a default implementation
|
||||
if (!this._defaultApiImpl) {
|
||||
let extensionPathsPretty = '';
|
||||
this._extensionPaths.forEach((value, index) => extensionPathsPretty += `\t${index} -> ${value.identifier.value}\n`);
|
||||
console.warn(`Could not identify extension for 'vscode' require call from ${parent.filename}. These are the extension path mappings: \n${extensionPathsPretty}`);
|
||||
this._defaultApiImpl = this._apiFactory(nullExtensionDescription, this._extensionRegistry, this._configProvider);
|
||||
}
|
||||
return this._defaultApiImpl;
|
||||
}
|
||||
}
|
||||
|
||||
interface IKeytarModule {
|
||||
getPassword(service: string, account: string): Promise<string | null>;
|
||||
setPassword(service: string, account: string, password: string): Promise<void>;
|
||||
deletePassword(service: string, account: string): Promise<boolean>;
|
||||
findPassword(service: string): Promise<string | null>;
|
||||
}
|
||||
|
||||
export class KeytarNodeModuleFactory implements INodeModuleFactory {
|
||||
public readonly nodeModuleName: string = 'keytar';
|
||||
|
||||
private alternativeNames: Set<string> | undefined;
|
||||
private _impl: IKeytarModule;
|
||||
|
||||
constructor(mainThreadKeytar: MainThreadKeytarShape, environment: IEnvironment) {
|
||||
if (environment.appRoot) {
|
||||
let appRoot = environment.appRoot.fsPath;
|
||||
if (process.platform === 'win32') {
|
||||
appRoot = appRoot.replace(/\\/g, '/');
|
||||
}
|
||||
if (appRoot[appRoot.length - 1] === '/') {
|
||||
appRoot = appRoot.substr(0, appRoot.length - 1);
|
||||
}
|
||||
this.alternativeNames = new Set();
|
||||
this.alternativeNames.add(`${appRoot}/node_modules.asar/keytar`);
|
||||
this.alternativeNames.add(`${appRoot}/node_modules/keytar`);
|
||||
}
|
||||
this._impl = {
|
||||
getPassword: (service: string, account: string): Promise<string | null> => {
|
||||
return mainThreadKeytar.$getPassword(service, account);
|
||||
},
|
||||
setPassword: (service: string, account: string, password: string): Promise<void> => {
|
||||
return mainThreadKeytar.$setPassword(service, account, password);
|
||||
},
|
||||
deletePassword: (service: string, account: string): Promise<boolean> => {
|
||||
return mainThreadKeytar.$deletePassword(service, account);
|
||||
},
|
||||
findPassword: (service: string): Promise<string | null> => {
|
||||
return mainThreadKeytar.$findPassword(service);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public load(request: string, parent: { filename: string; }): any {
|
||||
return this._impl;
|
||||
}
|
||||
|
||||
public alternaiveModuleName(name: string): string | undefined {
|
||||
const length = name.length;
|
||||
// We need at least something like: `?/keytar` which requires
|
||||
// more than 7 characters.
|
||||
if (length <= 7 || !this.alternativeNames) {
|
||||
return undefined;
|
||||
}
|
||||
const sep = length - 7;
|
||||
if ((name.charAt(sep) === '/' || name.charAt(sep) === '\\') && endsWith(name, 'keytar')) {
|
||||
name = name.replace(/\\/g, '/');
|
||||
if (this.alternativeNames.has(name)) {
|
||||
return 'keytar';
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
interface OpenOptions {
|
||||
wait: boolean;
|
||||
app: string | string[];
|
||||
}
|
||||
|
||||
interface IOriginalOpen {
|
||||
(target: string, options?: OpenOptions): Thenable<any>;
|
||||
}
|
||||
|
||||
interface IOpenModule {
|
||||
(target: string, options?: OpenOptions): Thenable<void>;
|
||||
}
|
||||
|
||||
export class OpenNodeModuleFactory implements INodeModuleFactory {
|
||||
|
||||
public readonly nodeModuleName: string[] = ['open', 'opn'];
|
||||
|
||||
private _extensionId: string | undefined;
|
||||
private _original: IOriginalOpen;
|
||||
private _impl: IOpenModule;
|
||||
|
||||
constructor(mainThreadWindow: MainThreadWindowShape, private _mainThreadTelemerty: MainThreadTelemetryShape, private readonly _extensionPaths: TernarySearchTree<IExtensionDescription>) {
|
||||
this._impl = (target, options) => {
|
||||
const uri: URI = URI.parse(target);
|
||||
// If we have options use the original method.
|
||||
if (options) {
|
||||
return this.callOriginal(target, options);
|
||||
}
|
||||
if (uri.scheme === 'http' || uri.scheme === 'https') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
} else if (uri.scheme === 'mailto') {
|
||||
return mainThreadWindow.$openUri(uri);
|
||||
}
|
||||
return this.callOriginal(target, options);
|
||||
};
|
||||
}
|
||||
|
||||
public load(request: string, parent: { filename: string; }, isMain: any, original: LoadFunction): any {
|
||||
// get extension id from filename and api for extension
|
||||
const extension = this._extensionPaths.findSubstr(URI.file(parent.filename).fsPath);
|
||||
if (extension) {
|
||||
this._extensionId = extension.identifier.value;
|
||||
this.sendShimmingTelemetry();
|
||||
}
|
||||
|
||||
this._original = original(request, parent, isMain);
|
||||
return this._impl;
|
||||
}
|
||||
|
||||
private callOriginal(target: string, options: OpenOptions | undefined): Thenable<any> {
|
||||
this.sendNoForwardTelemetry();
|
||||
return this._original(target, options);
|
||||
}
|
||||
|
||||
private sendShimmingTelemetry(): void {
|
||||
if (!this._extensionId) {
|
||||
return;
|
||||
}
|
||||
/* __GDPR__
|
||||
"shimming.open" : {
|
||||
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemerty.$publicLog('shimming.open', { extension: this._extensionId });
|
||||
}
|
||||
|
||||
private sendNoForwardTelemetry(): void {
|
||||
if (!this._extensionId) {
|
||||
return;
|
||||
}
|
||||
/* __GDPR__
|
||||
"shimming.open.call.noForward" : {
|
||||
"extension": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }
|
||||
}
|
||||
*/
|
||||
this._mainThreadTelemerty.$publicLog('shimming.open.call.noForward', { extension: this._extensionId });
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user