Merge from vscode 3d67364fbfcf676d93be64f949e9b33e7f1b969e (#5028)

This commit is contained in:
Anthony Dresser
2019-04-14 22:29:14 -07:00
committed by GitHub
parent 6dbf757385
commit 57242a2e13
210 changed files with 4898 additions and 3018 deletions

View File

@@ -0,0 +1,4 @@
#!/usr/bin/env bash
set -e
yarn gulp vscode-darwin-min
yarn gulp upload-vscode-sourcemaps

View File

@@ -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

View 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

View File

@@ -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

View File

@@ -0,0 +1,3 @@
#!/usr/bin/env bash
set -e
yarn gulp "vscode-linux-$VSCODE_ARCH-min"

View File

@@ -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'

View 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)

View 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" }

View File

@@ -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'

View 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 }

View File

@@ -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' })

View File

@@ -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}}

View File

@@ -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}}

View File

@@ -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": {

View File

@@ -1031,7 +1031,7 @@
],
"markdownDescription": "%config.path%",
"default": null,
"scope": "application"
"scope": "machine"
},
"git.autoRepositoryDetection": {
"type": [

View File

@@ -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) {

View File

@@ -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' })

View File

@@ -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"

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"
}

View File

@@ -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"

View File

@@ -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"

View File

@@ -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)));
}

View File

@@ -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`);
});
});
});

View File

@@ -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);
}
});
});
});
});
}

View 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==

View File

@@ -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"
}
}
}

View File

@@ -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 $@

View File

@@ -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 $?

View File

@@ -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

View File

@@ -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
View File

@@ -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

View File

@@ -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));

View File

@@ -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'
});
}
}

View File

@@ -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;
}
}

View File

@@ -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",

View File

@@ -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'
};

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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();

View File

@@ -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;

View File

@@ -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':

View 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

View 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

View 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

View File

@@ -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[] = [];

View File

@@ -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

View File

@@ -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,

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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
};

View File

@@ -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
View 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

View File

@@ -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]));
}
}
}

View File

@@ -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);

View File

@@ -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');

View File

@@ -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);
});

View File

@@ -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;

View File

@@ -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');

View File

@@ -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);
});

View File

@@ -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');

View File

@@ -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))
};
}));

View File

@@ -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 {

View File

@@ -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
View File

@@ -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 {

View File

@@ -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;

View File

@@ -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.

View File

@@ -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();

View File

@@ -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'));
}
}
}

View File

@@ -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>;
}

View File

@@ -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;
}

View File

@@ -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) });
}
}
}

View File

@@ -56,6 +56,7 @@ export interface IssueReporterData extends WindowData {
styles: IssueReporterStyles;
enabledExtensions: IssueReporterExtensionData[];
issueType?: IssueType;
extensionId?: string;
}
export interface ISettingSearchResult {

View File

@@ -30,7 +30,8 @@ export const enum ProgressLocation {
Scm = 3,
Extensions = 5,
Window = 10,
Notification = 15
Notification = 15,
Dialog = 20
}
export interface IProgressOptions {

View File

@@ -19,7 +19,6 @@ export interface IRemoteAgentEnvironment {
userHome: URI;
extensions: IExtensionDescription[];
os: OperatingSystem;
syncExtensions: boolean;
}
export interface RemoteAgentConnectionContext {

View File

@@ -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]));
}
}

View File

@@ -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;
}
}

View 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;
}
}

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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({

View 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);
});
}
}

View File

@@ -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
View File

@@ -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`.
*/

View File

@@ -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

View File

@@ -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)));
}
}

View File

@@ -162,7 +162,7 @@ class RemoteSearchProvider implements ISearchResultProvider, IDisposable {
});
} else {
searchOp.addMatch({
resource: URI.revive(result)
resource: URI.revive(<UriComponents>result)
});
}
});

View File

@@ -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';

View 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 {

View File

@@ -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

View File

@@ -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;
});
}

View File

@@ -0,0 +1,59 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { 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();
}
}

View File

@@ -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 {

View File

@@ -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
);
}

View File

@@ -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> {

View File

@@ -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,
};
}

View File

@@ -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