diff --git a/.gitignore b/.gitignore index f923956845..3ffb11ed18 100644 --- a/.gitignore +++ b/.gitignore @@ -19,9 +19,6 @@ out-vscode-reh/ out-vscode-reh-min/ out-vscode-reh-pkg/ **/node_modules -src/vs/server -resources/server -build/node_modules coverage/ test_data/ test-results/ diff --git a/.vscode/launch.json b/.vscode/launch.json index bc148b2186..4ae9375942 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -218,4 +218,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/.yarnrc b/.yarnrc index 7e63643de0..beab9f70b9 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "4.2.3" +target "3.1.8" runtime "electron" diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..65c8a42b8d --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1 @@ +This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. diff --git a/build/.nativeignore b/build/.nativeignore index 17ced53438..a04b4dbc23 100644 --- a/build/.nativeignore +++ b/build/.nativeignore @@ -1,8 +1,5 @@ # cleanup rules for native node modules, .gitignore style -nan/** -*/node_modules/nan/** - fsevents/binding.gyp fsevents/fsevents.cc fsevents/build/** @@ -86,7 +83,6 @@ node-pty/binding.gyp node-pty/build/** node-pty/src/** node-pty/tools/** -node-pty/deps/** !node-pty/build/Release/*.exe !node-pty/build/Release/*.dll !node-pty/build/Release/*.node diff --git a/build/azure-pipelines/common/installDistro.ts b/build/azure-pipelines/common/installDistro.ts new file mode 100644 index 0000000000..ca3795285b --- /dev/null +++ b/build/azure-pipelines/common/installDistro.ts @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as cp from 'child_process'; +import * as path from 'path'; + +function yarnInstall(packageName: string): void { + cp.execSync(`yarn add --no-lockfile ${packageName}`); + cp.execSync(`yarn add --no-lockfile ${packageName}`, { cwd: path.join( process.cwd(), 'remote') }); +} + +const product = require('../../../product.json'); +const dependencies = product.dependencies || {} as { [name: string]: string; }; + +Object.keys(dependencies).forEach(name => { + const url = dependencies[name]; + yarnInstall(url); +}); \ No newline at end of file diff --git a/build/azure-pipelines/common/installDistroDependencies.ts b/build/azure-pipelines/common/installDistroDependencies.ts deleted file mode 100644 index c7284708c6..0000000000 --- a/build/azure-pipelines/common/installDistroDependencies.ts +++ /dev/null @@ -1,38 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as cp from 'child_process'; -import * as path from 'path'; -import * as fs from 'fs'; - -function yarnInstall(packageName: string, cwd: string): void { - console.log(`yarn add --no-lockfile ${packageName}`, cwd); - cp.execSync(`yarn add --no-lockfile ${packageName}`, { cwd, stdio: 'inherit' }); -} - -/** - * Install additional dependencies listed on each quality `package.json` file. - */ -function main() { - const quality = process.env['VSCODE_QUALITY']; - - if (!quality) { - throw new Error('Missing VSCODE_QUALITY, can\'t install distro'); - } - - const rootPath = path.dirname(path.dirname(path.dirname(__dirname))); - const qualityPath = path.join(rootPath, 'quality', quality); - const packagePath = path.join(qualityPath, 'package.json'); - const pkg = JSON.parse(fs.readFileSync(packagePath, 'utf8')); - const dependencies = pkg.dependencies || {} as { [name: string]: string; }; - - Object.keys(dependencies).forEach(name => { - const url = dependencies[name]; - const cwd = process.argv.length < 3 ? process.cwd() : path.join(process.cwd(), process.argv[2]); - yarnInstall(url, cwd); - }); -} - -main(); \ No newline at end of file diff --git a/build/azure-pipelines/common/symbols.ts b/build/azure-pipelines/common/symbols.ts index 69b8f4be39..a334ee1195 100644 --- a/build/azure-pipelines/common/symbols.ts +++ b/build/azure-pipelines/common/symbols.ts @@ -36,6 +36,7 @@ export interface IVersionAccessor extends IApplicationAccessor { enum Platform { WIN_32 = 'win32-ia32', WIN_64 = 'win32-x64', + LINUX_32 = 'linux-ia32', LINUX_64 = 'linux-x64', MAC_OS = 'darwin-x64' } @@ -190,7 +191,7 @@ if (process.platform === 'darwin') { } else if (process.platform === 'win32') { platform = is64 ? Platform.WIN_64 : Platform.WIN_32; } else { - platform = Platform.LINUX_64; + platform = is64 ? Platform.LINUX_64 : Platform.LINUX_32; } // Create version and upload symbols in HockeyApp diff --git a/build/azure-pipelines/darwin/product-build-darwin.yml b/build/azure-pipelines/darwin/product-build-darwin.yml index f136f2b449..5d6ec8c2cf 100644 --- a/build/azure-pipelines/darwin/product-build-darwin.yml +++ b/build/azure-pipelines/darwin/product-build-darwin.yml @@ -34,8 +34,7 @@ steps: yarn gulp mixin yarn gulp hygiene yarn monaco-compile-check - node build/azure-pipelines/common/installDistroDependencies.js - node build/azure-pipelines/common/installDistroDependencies.js remote + node build/azure-pipelines/common/installDistro.js node build/lib/builtInExtensions.js displayName: Prepare build diff --git a/build/azure-pipelines/linux/build-arm.sh b/build/azure-pipelines/linux/build-arm.sh deleted file mode 100755 index 4f01bc9a7e..0000000000 --- a/build/azure-pipelines/linux/build-arm.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -e -echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/prebuild-arm.sh b/build/azure-pipelines/linux/prebuild-arm.sh deleted file mode 100755 index 4f01bc9a7e..0000000000 --- a/build/azure-pipelines/linux/prebuild-arm.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -e -echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/product-build-linux-arm.yml b/build/azure-pipelines/linux/product-build-linux-arm.yml deleted file mode 100644 index 55350cce29..0000000000 --- a/build/azure-pipelines/linux/product-build-linux-arm.yml +++ /dev/null @@ -1,65 +0,0 @@ -steps: -- task: NodeTool@0 - inputs: - versionSpec: "10.15.1" - -- task: geeklearningio.gl-vsts-tasks-yarn.yarn-installer-task.YarnInstaller@2 - inputs: - versionSpec: "1.10.1" - -- task: AzureKeyVault@1 - displayName: 'Azure Key Vault: Get Secrets' - inputs: - azureSubscription: 'vscode-builds-subscription' - KeyVaultName: vscode - -- task: Docker@1 - displayName: 'Pull image' - inputs: - azureSubscriptionEndpoint: 'vscode-builds-subscription' - azureContainerRegistry: vscodehub.azurecr.io - command: 'Run an image' - imageName: 'vscode-linux-build-agent:armhf' - containerCommand: uname - -- script: | - set -e - - cat << EOF > ~/.netrc - machine monacotools.visualstudio.com - password $(devops-pat) - machine github.com - login vscode - password $(github-distro-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 - yarn gulp mixin - yarn gulp hygiene - yarn monaco-compile-check - ./build/azure-pipelines/linux/prebuild-arm.sh - displayName: Prepare build - -- script: | - set -e - ./build/azure-pipelines/linux/build-arm.sh - displayName: Build - -- script: | - set -e - AZURE_DOCUMENTDB_MASTERKEY="$(builds-docdb-key-readwrite)" \ - AZURE_STORAGE_ACCESS_KEY_2="$(vscode-storage-key)" \ - VSCODE_MIXIN_PASSWORD="$(github-distro-mixin-password)" \ - VSCODE_HOCKEYAPP_TOKEN="$(vscode-hockeyapp-token)" \ - ./build/azure-pipelines/linux/publish-arm.sh - displayName: Publish - -- task: ms.vss-governance-buildtask.governance-build-task-component-detection.ComponentGovernanceComponentDetection@0 - displayName: 'Component Detection' - continueOnError: true \ No newline at end of file diff --git a/build/azure-pipelines/linux/product-build-linux.yml b/build/azure-pipelines/linux/product-build-linux.yml index c1386b93f7..f727e30d25 100644 --- a/build/azure-pipelines/linux/product-build-linux.yml +++ b/build/azure-pipelines/linux/product-build-linux.yml @@ -16,6 +16,9 @@ steps: - script: | set -e export npm_config_arch="$(VSCODE_ARCH)" + if [[ "$(VSCODE_ARCH)" == "ia32" ]]; then + export PKG_CONFIG_PATH="/usr/lib/i386-linux-gnu/pkgconfig" + fi cat << EOF > ~/.netrc machine monacotools.visualstudio.com @@ -35,8 +38,7 @@ steps: yarn gulp mixin yarn gulp hygiene yarn monaco-compile-check - node build/azure-pipelines/common/installDistroDependencies.js - node build/azure-pipelines/common/installDistroDependencies.js remote + node build/azure-pipelines/common/installDistro.js node build/lib/builtInExtensions.js displayName: Prepare build diff --git a/build/azure-pipelines/linux/publish-arm.sh b/build/azure-pipelines/linux/publish-arm.sh deleted file mode 100755 index 4f01bc9a7e..0000000000 --- a/build/azure-pipelines/linux/publish-arm.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -set -e -echo 'noop' \ No newline at end of file diff --git a/build/azure-pipelines/linux/publish.sh b/build/azure-pipelines/linux/publish.sh index a6b48389d5..0f864600bd 100755 --- a/build/azure-pipelines/linux/publish.sh +++ b/build/azure-pipelines/linux/publish.sh @@ -5,6 +5,8 @@ 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)" @@ -37,7 +39,7 @@ node build/azure-pipelines/common/symbols.js "$VSCODE_MIXIN_PASSWORD" "$VSCODE_H # Publish DEB yarn gulp "vscode-linux-$VSCODE_ARCH-build-deb" PLATFORM_DEB="linux-deb-$VSCODE_ARCH" -DEB_ARCH="amd64" +[[ "$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" @@ -46,7 +48,7 @@ node build/azure-pipelines/common/publish.js "$VSCODE_QUALITY" "$PLATFORM_DEB" p # Publish RPM yarn gulp "vscode-linux-$VSCODE_ARCH-build-rpm" PLATFORM_RPM="linux-rpm-$VSCODE_ARCH" -RPM_ARCH="x86_64" +[[ "$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" diff --git a/build/azure-pipelines/product-build.yml b/build/azure-pipelines/product-build.yml index ac9ce03b59..c8bedfbffc 100644 --- a/build/azure-pipelines/product-build.yml +++ b/build/azure-pipelines/product-build.yml @@ -1,8 +1,11 @@ resources: containers: - container: vscode-x64 - image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 endpoint: VSCodeHub + image: vscodehub.azurecr.io/vscode-linux-build-agent:x64 + - container: vscode-ia32 + endpoint: VSCodeHub + image: vscodehub.azurecr.io/vscode-linux-build-agent:ia32 - container: snapcraft image: snapcore/snapcraft @@ -46,14 +49,15 @@ jobs: steps: - template: linux/snap-build-linux.yml -- job: LinuxArmhf - condition: eq(variables['VSCODE_BUILD_LINUX_ARMHF'], 'true') +- job: Linux32 + condition: eq(variables['VSCODE_BUILD_LINUX_32BIT'], 'true') pool: vmImage: 'Ubuntu-16.04' variables: - VSCODE_ARCH: armhf + VSCODE_ARCH: ia32 + container: vscode-ia32 steps: - - template: linux/product-build-linux-arm.yml + - template: linux/product-build-linux.yml - job: macOS condition: eq(variables['VSCODE_BUILD_MACOS'], 'true') @@ -71,7 +75,7 @@ jobs: - Windows32 - Linux - LinuxSnap - - LinuxArmhf + - Linux32 - macOS steps: - template: sync-mooncake.yml \ No newline at end of file diff --git a/build/azure-pipelines/win32/product-build-win32.yml b/build/azure-pipelines/win32/product-build-win32.yml index 339bdde1b9..8a6a6abb65 100644 --- a/build/azure-pipelines/win32/product-build-win32.yml +++ b/build/azure-pipelines/win32/product-build-win32.yml @@ -35,8 +35,7 @@ steps: exec { yarn gulp mixin } exec { yarn gulp hygiene } exec { yarn monaco-compile-check } - exec { node build/azure-pipelines/common/installDistroDependencies.js } - exec { node build/azure-pipelines/common/installDistroDependencies.js remote } + exec { node build/azure-pipelines/common/installDistro.js } exec { node build/lib/builtInExtensions.js } displayName: Prepare build diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index bfe3f0f6fd..fe5cbcfc56 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -7,111 +7,10 @@ const gulp = require('gulp'); -const path = require('path'); -const es = require('event-stream'); -const util = require('./lib/util'); -const task = require('./lib/task'); - -const vfs = require('vinyl-fs'); -const flatmap = require('gulp-flatmap'); -const gunzip = require('gulp-gunzip'); -const untar = require('gulp-untar'); -const File = require('vinyl'); -const fs = require('fs'); - -const REPO_ROOT = path.dirname(__dirname); - const noop = () => { return Promise.resolve(); }; gulp.task('vscode-reh-win32-ia32-min', noop); gulp.task('vscode-reh-win32-x64-min', noop); gulp.task('vscode-reh-darwin-min', noop); gulp.task('vscode-reh-linux-x64-min', noop); -gulp.task('vscode-reh-linux-armhf-min', noop); - - -function getNodeVersion() { - const yarnrc = fs.readFileSync(path.join(REPO_ROOT, 'remote', '.yarnrc'), 'utf8'); - const target = /^target "(.*)"$/m.exec(yarnrc)[1]; - return target; -} - -function ensureDirs(dirPath) { - if (!fs.existsSync(dirPath)) { - ensureDirs(path.dirname(dirPath)); - fs.mkdirSync(dirPath); - } -} - -/* Downloads the node executable used for the remote server to ./build/node-remote */ -gulp.task(task.define('node-remote', () => { - const VERSION = getNodeVersion(); - const nodePath = path.join('.build', 'node-remote'); - const nodeVersionPath = path.join(nodePath, 'version'); - if (!fs.existsSync(nodeVersionPath) || fs.readFileSync(nodeVersionPath).toString() !== VERSION) { - ensureDirs(nodePath); - util.rimraf(nodePath); - fs.writeFileSync(nodeVersionPath, VERSION); - return nodejs(process.platform, process.arch).pipe(vfs.dest(nodePath)); - } - return vfs.src(nodePath); -})); - -function nodejs(platform, arch) { - const VERSION = getNodeVersion(); - - if (arch === 'ia32') { - arch = 'x86'; - } - - if (platform === 'win32') { - const downloadPath = `/dist/v${VERSION}/win-${arch}/node.exe`; - - return ( - util.download({ host: 'nodejs.org', path: downloadPath }) - .pipe(es.through(function (data) { - // base comes in looking like `https:\nodejs.org\dist\v10.2.1\win-x64\node.exe` - this.emit('data', new File({ - path: data.path, - base: data.base.replace(/\\node\.exe$/, ''), - contents: data.contents, - stat: { - isFile: true, - mode: /* 100755 */ 33261 - } - })); - })) - ); - } - - if (platform === 'darwin') { - arch = 'x64'; - } - - if (arch === 'armhf') { - arch = 'armv7l'; - } - - const downloadPath = `/dist/v${VERSION}/node-v${VERSION}-${platform}-${arch}.tar.gz`; - - return ( - util.download({ host: 'nodejs.org', path: downloadPath }) - .pipe(flatmap(stream => stream.pipe(gunzip()).pipe(untar()))) - .pipe(es.through(function (data) { - // base comes in looking like `https:/nodejs.org/dist/v8.9.3/node-v8.9.3-darwin-x64.tar.gz` - // => we must remove the `.tar.gz` - // Also, keep only bin/node - if (/\/bin\/node$/.test(data.path)) { - this.emit('data', new File({ - path: data.path.replace(/bin\/node$/, 'node'), - base: data.base.replace(/\.tar\.gz$/, ''), - contents: data.contents, - stat: { - isFile: true, - mode: /* 100755 */ 33261 - } - })); - } - })) - ); -} +gulp.task('vscode-reh-linux-arm-min', noop); diff --git a/build/gulpfile.vscode.js b/build/gulpfile.vscode.js index d0bebb5af2..3c4b82555d 100644 --- a/build/gulpfile.vscode.js +++ b/build/gulpfile.vscode.js @@ -402,7 +402,6 @@ function packageTask(platform, arch, sourceFolderName, destinationFolderName, op .pipe(replace('@@VERSION@@', version)) .pipe(replace('@@COMMIT@@', commit)) .pipe(replace('@@APPNAME@@', product.applicationName)) - .pipe(replace('@@DATAFOLDER@@', product.dataFolderName)) .pipe(replace('@@QUALITY@@', quality)) .pipe(rename(function (f) { f.basename = product.applicationName; f.extname = ''; }))); @@ -538,14 +537,14 @@ gulp.task('vscode-translations-import', function () { // Sourcemaps gulp.task('upload-vscode-sourcemaps', () => { - const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) // client source-maps only + const vs = gulp.src('out-vscode-min/**/*.map', { base: 'out-vscode-min' }) .pipe(es.mapSync(f => { f.path = `${f.base}/core/${f.relative}`; return f; })); - const extensionsOut = gulp.src(['extensions/**/out/**/*.map', '!extensions/**/node_modules/**'], { base: '.' }); - const extensionsDist = gulp.src(['extensions/**/dist/**/*.map', '!extensions/**/node_modules/**'], { base: '.' }); + const extensionsOut = gulp.src('extensions/**/out/**/*.map', { base: '.' }); + const extensionsDist = gulp.src('extensions/**/dist/**/*.map', { base: '.' }); return es.merge(vs, extensionsOut, extensionsDist) .pipe(es.through(function (data) { diff --git a/build/gulpfile.vscode.linux.js b/build/gulpfile.vscode.linux.js index 7cd31a1a18..a563ed929f 100644 --- a/build/gulpfile.vscode.linux.js +++ b/build/gulpfile.vscode.linux.js @@ -23,7 +23,7 @@ const commit = util.getVersion(root); const linuxPackageRevision = Math.floor(new Date().getTime() / 1000); function getDebPackageArch(arch) { - return { x64: 'amd64', arm: 'armhf', arm64: "arm64" }[arch]; + return { x64: 'amd64', ia32: 'i386', arm: 'armhf', arm64: "arm64" }[arch]; } function prepareDebPackage(arch) { @@ -115,7 +115,7 @@ function getRpmBuildPath(rpmArch) { } function getRpmPackageArch(arch) { - return { x64: 'x86_64', arm: 'armhf', arm64: "arm64" }[arch]; + return { x64: 'x86_64', ia32: 'i386', arm: 'armhf', arm64: "arm64" }[arch]; } function prepareRpmPackage(arch) { @@ -241,6 +241,7 @@ function buildSnapPackage(arch) { } const BUILD_TARGETS = [ + { arch: 'ia32' }, { arch: 'x64' }, { arch: 'arm' }, { arch: 'arm64' }, diff --git a/build/lib/electron.js b/build/lib/electron.js index 2c981fe95c..ee737e9d60 100644 --- a/build/lib/electron.js +++ b/build/lib/electron.js @@ -24,7 +24,7 @@ module.exports.getElectronVersion = getElectronVersion; if (require.main === module) { const version = getElectronVersion(); const versionFile = path.join(root, '.build', 'electron', 'version'); - const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `${version}`; + const isUpToDate = fs.existsSync(versionFile) && fs.readFileSync(versionFile, 'utf8') === `v${version}`; process.exit(isUpToDate ? 0 : 1); } diff --git a/build/lib/i18n.resources.json b/build/lib/i18n.resources.json index 32b0e6fb4c..22d3d165c3 100644 --- a/build/lib/i18n.resources.json +++ b/build/lib/i18n.resources.json @@ -38,6 +38,10 @@ "name": "vs/workbench/contrib/codeEditor", "project": "vscode-workbench" }, + { + "name": "vs/workbench/contrib/codeinset", + "project": "vscode-workbench" + }, { "name": "vs/workbench/contrib/callHierarchy", "project": "vscode-workbench" diff --git a/build/lib/i18n.ts b/build/lib/i18n.ts index 616a672ce4..7bb98cbab7 100644 --- a/build/lib/i18n.ts +++ b/build/lib/i18n.ts @@ -25,7 +25,7 @@ function log(message: any, ...rest: any[]): void { export interface Language { id: string; // language id, e.g. zh-tw, de - translationId?: string; // language id used in translation tools, e.g. zh-hant, de (optional, if not set, the id is used) + translationId?: string; // language id used in translation tools, e.g zh-hant, de (optional, if not set, the id is used) folderName?: string; // language specific folder name, e.g. cht, deu (optional, if not set, the id is used) } diff --git a/build/lib/watch/package.json b/build/lib/watch/package.json index 3afffdec7d..0d03134015 100644 --- a/build/lib/watch/package.json +++ b/build/lib/watch/package.json @@ -4,7 +4,6 @@ "description": "", "author": "Microsoft ", "private": true, - "license": "MIT", "devDependencies": { "gulp-watch": "^4.3.9" } diff --git a/build/package.json b/build/package.json index 4dad3474cd..8fe67192a0 100644 --- a/build/package.json +++ b/build/package.json @@ -1,7 +1,6 @@ { "name": "azuredatastudio-oss-dev-build", "version": "1.0.0", - "license": "MIT", "devDependencies": { "@types/ansi-colors": "^3.2.0", "@types/azure": "0.9.19", @@ -44,7 +43,7 @@ "request": "^2.85.0", "tslint": "^5.9.1", "service-downloader": "github:anthonydresser/service-downloader#0.1.5", - "typescript": "3.5.1", + "typescript": "3.4.5", "vsce": "1.48.0", "xml2js": "^0.4.17" }, diff --git a/build/win32/i18n/messages.en.isl b/build/win32/i18n/messages.en.isl index a6aab59b95..4bd6c75ad4 100644 --- a/build/win32/i18n/messages.en.isl +++ b/build/win32/i18n/messages.en.isl @@ -2,7 +2,7 @@ AddContextMenuFiles=Add "Open with %1" action to Windows Explorer file context menu AddContextMenuFolders=Add "Open with %1" action to Windows Explorer directory context menu AssociateWithFiles=Register %1 as an editor for supported file types -AddToPath=Add to PATH (requires shell restart) +AddToPath=Add to PATH (available after restart) RunAfter=Run %1 after installation Other=Other: SourceFile=%1 Source File \ No newline at end of file diff --git a/build/yarn.lock b/build/yarn.lock index 8551be127d..7a77cf1451 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -3201,10 +3201,10 @@ typed-rest-client@^0.9.0: tunnel "0.0.4" underscore "1.8.3" -typescript@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202" - integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw== +typescript@3.4.5: + version "3.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" + integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== uc.micro@^1.0.1, uc.micro@^1.0.5: version "1.0.5" diff --git a/cgmanifest.json b/cgmanifest.json index 6cebbffd6b..01cdd8df5f 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -6,7 +6,7 @@ "git": { "name": "chromium", "repositoryUrl": "https://chromium.googlesource.com/chromium/src", - "commitHash": "c6a08e5368de4352903e702cde750b33239a50ab" + "commitHash": "164c37e3f235134c88e80fac2a182cfba3f07f00" } }, "licenseDetail": [ @@ -40,7 +40,20 @@ "SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." ], "isOnlyProductionDependency": true, - "version": "69.0.3497.128" + "version": "66.0.3359.181" + }, + { + "component": { + "type": "git", + "git": { + "name": "libchromiumcontent", + "repositoryUrl": "https://github.com/electron/libchromiumcontent", + "commitHash": "7ea271f92018b1eeb8e70ec6de8c29f9758a0c05" + } + }, + "isOnlyProductionDependency": true, + "license": "MIT", + "version": "66.0.3359.181" }, { "component": { @@ -48,11 +61,11 @@ "git": { "name": "nodejs", "repositoryUrl": "https://github.com/nodejs/node", - "commitHash": "8c70b2084ce5f76ea1e3b3c4ccdeee4483fe338b" + "commitHash": "5cbb905c1af7cea2d709932d59827d7c6d03ef4a" } }, "isOnlyProductionDependency": true, - "version": "10.11.0" + "version": "10.2.0" }, { "component": { @@ -60,12 +73,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "c1b5a1cfc8a14a337540193daecfa5d0f50dd7bb" + "commitHash": "e84a6860e35e14b4031b88bb9b49841cdb89a305" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "4.2.3" + "version": "3.1.8" }, { "component": { @@ -98,11 +111,11 @@ "git": { "name": "vscode-octicons-font", "repositoryUrl": "https://github.com/Microsoft/vscode-octicons-font", - "commitHash": "415cd5b42ab699b6b46c0bf011ada0a2ae50bfb4" + "commitHash": "4f69de3a233ed501c2098e33047e116ac2fbbf42" } }, "license": "MIT", - "version": "1.3.1" + "version": "1.1.0" }, { "component": { diff --git a/extensions/bat/package.json b/extensions/bat/package.json index 00bd84e4ae..c54d1a4ce5 100644 --- a/extensions/bat/package.json +++ b/extensions/bat/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js mmims/language-batchfile grammars/batchfile.cson ./syntaxes/batchfile.tmLanguage.json" diff --git a/extensions/configuration-editing/package.json b/extensions/configuration-editing/package.json index e555d61457..e9f9e255f3 100644 --- a/extensions/configuration-editing/package.json +++ b/extensions/configuration-editing/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "^1.0.0" }, @@ -109,6 +108,6 @@ ] }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^10.12.21" } } diff --git a/extensions/configuration-editing/schemas/devContainer.schema.json b/extensions/configuration-editing/schemas/devContainer.schema.json index 55950a9021..38b3c640c5 100644 --- a/extensions/configuration-editing/schemas/devContainer.schema.json +++ b/extensions/configuration-editing/schemas/devContainer.schema.json @@ -5,7 +5,6 @@ "type": "object", "definitions": { "devContainerCommon": { - "type": "object", "properties": { "name": { "type": "string", @@ -19,14 +18,11 @@ } }, "settings": { - "$ref": "vscode://schemas/settings/machine", + "type": "object", "description": "Machine specific settings that should be copied into the container." }, "postCreateCommand": { - "type": [ - "string", - "array" - ], + "type": ["string", "array"], "description": "A command to run after creating the container. If this is a single string, it will be run in a shell. If this is an array of strings, it will be run as a single command without shell.", "items": { "type": "string" @@ -39,20 +35,12 @@ } }, "nonComposeBase": { - "type": "object", "properties": { "appPort": { - "type": [ - "integer", - "string", - "array" - ], + "type": ["integer", "string", "array"], "description": "Application ports that are exposed by the container. This can be a single port or an array of ports. Each port can be a number or a string. A number is mapped to the same port on the host. A string is passed to Docker unchanged and can be used to map ports differently, e.g. \"8000:8010\".", "items": { - "type": [ - "integer", - "string" - ] + "type": ["integer", "string"] } }, "runArgs": { @@ -64,10 +52,7 @@ }, "shutdownAction": { "type": "string", - "enum": [ - "none", - "stopContainer" - ], + "enum": ["none", "stopContainer"], "description": "Action to take when VS Code is shutting down. The default is to stop the container." }, "overrideCommand": { @@ -85,7 +70,6 @@ } }, "dockerFileContainer": { - "type": "object", "properties": { "dockerFile": { "type": "string", @@ -96,30 +80,21 @@ "description": "The location of the context folder for building the Docker image. The path is relative to the folder containing the `devcontainer.json` file." } }, - "required": [ - "dockerFile" - ] + "required": ["dockerFile"] }, "imageContainer": { - "type": "object", "properties": { "image": { "type": "string", "description": "The docker image that will be used to create the container." } }, - "required": [ - "image" - ] + "required": ["image"] }, "composeContainer": { - "type": "object", "properties": { "dockerComposeFile": { - "type": [ - "string", - "array" - ], + "type": ["string", "array"], "description": "The name of the docker-compose file(s) used to start the services.", "items": { "type": "string" @@ -135,18 +110,11 @@ }, "shutdownAction": { "type": "string", - "enum": [ - "none", - "stopCompose" - ], + "enum": ["none", "stopCompose"], "description": "Action to take when VS Code is shutting down. The default is to stop the containers." } }, - "required": [ - "dockerComposeFile", - "service", - "workspaceFolder" - ] + "required": ["dockerComposeFile", "service", "workspaceFolder"] } }, "allOf": [ diff --git a/extensions/configuration-editing/yarn.lock b/extensions/configuration-editing/yarn.lock index ce653f097a..49c4716606 100644 --- a/extensions/configuration-editing/yarn.lock +++ b/extensions/configuration-editing/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== jsonc-parser@2.0.2: version "2.0.2" diff --git a/extensions/css-language-features/server/src/test/links.test.ts b/extensions/css-language-features/server/src/test/links.test.ts deleted file mode 100644 index ff0aae4390..0000000000 --- a/extensions/css-language-features/server/src/test/links.test.ts +++ /dev/null @@ -1,79 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ -import 'mocha'; -import * as assert from 'assert'; -import Uri from 'vscode-uri'; -import { resolve } from 'path'; -import { TextDocument, DocumentLink } from 'vscode-languageserver-types'; -import { WorkspaceFolder } from 'vscode-languageserver-protocol'; -import { getCSSLanguageService } from 'vscode-css-languageservice'; -import { getDocumentContext } from '../utils/documentContext'; - -export interface ItemDescription { - offset: number; - value: string; - target: string; -} - -suite('Links', () => { - const cssLanguageService = getCSSLanguageService(); - - let assertLink = function (links: DocumentLink[], expected: ItemDescription, document: TextDocument) { - let matches = links.filter(link => { - return document.offsetAt(link.range.start) === expected.offset; - }); - - assert.equal(matches.length, 1, `${expected.offset} should only existing once: Actual: ${links.map(l => document.offsetAt(l.range.start)).join(', ')}`); - let match = matches[0]; - assert.equal(document.getText(match.range), expected.value); - assert.equal(match.target, expected.target); - }; - - function assertLinks(value: string, expected: ItemDescription[], testUri: string, workspaceFolders?: WorkspaceFolder[], lang: string = 'css'): void { - const offset = value.indexOf('|'); - value = value.substr(0, offset) + value.substr(offset + 1); - - const document = TextDocument.create(testUri, lang, 0, value); - - if (!workspaceFolders) { - workspaceFolders = [{ name: 'x', uri: testUri.substr(0, testUri.lastIndexOf('/')) }]; - } - - const context = getDocumentContext(testUri, workspaceFolders); - - const stylesheet = cssLanguageService.parseStylesheet(document); - let links = cssLanguageService.findDocumentLinks(document, stylesheet, context)!; - - assert.equal(links.length, expected.length); - - for (let item of expected) { - assertLink(links, item, document); - } - } - - function getTestResource(path: string) { - return Uri.file(resolve(__dirname, '../../test/linksTestFixtures', path)).toString(); - } - - test('url links', function () { - - let testUri = getTestResource('about.css'); - let folders = [{ name: 'x', uri: getTestResource('') }]; - - assertLinks('html { background-image: url("hello.html|")', - [{ offset: 29, value: '"hello.html"', target: getTestResource('hello.html') }], testUri, folders - ); - }); - - test('node module resolving', function () { - - let testUri = getTestResource('about.css'); - let folders = [{ name: 'x', uri: getTestResource('') }]; - - assertLinks('html { background-image: url("~foo/hello.html|")', - [{ offset: 29, value: '"~foo/hello.html"', target: getTestResource('node_modules/foo/hello.html') }], testUri, folders - ); - }); -}); \ No newline at end of file diff --git a/extensions/css-language-features/server/test/linksTestFixtures/.gitignore b/extensions/css-language-features/server/test/linksTestFixtures/.gitignore deleted file mode 100644 index d591cdfd50..0000000000 --- a/extensions/css-language-features/server/test/linksTestFixtures/.gitignore +++ /dev/null @@ -1 +0,0 @@ -!/node_modules \ No newline at end of file diff --git a/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json b/extensions/css-language-features/server/test/linksTestFixtures/node_modules/foo/package.json deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/extensions/docker/package.json b/extensions/docker/package.json index f5f2f795fc..41df24723f 100644 --- a/extensions/docker/package.json +++ b/extensions/docker/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js moby/moby contrib/syntax/textmate/Docker.tmbundle/Syntaxes/Dockerfile.tmLanguage ./syntaxes/docker.tmLanguage.json" diff --git a/extensions/extension-editing/package.json b/extensions/extension-editing/package.json index 9c07a2568a..52159b965b 100644 --- a/extensions/extension-editing/package.json +++ b/extensions/extension-editing/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "^1.4.0" }, @@ -54,6 +53,6 @@ }, "devDependencies": { "@types/markdown-it": "0.0.2", - "@types/node": "^10.14.8" + "@types/node": "^10.12.21" } } diff --git a/extensions/extension-editing/yarn.lock b/extensions/extension-editing/yarn.lock index 971bf580ba..720c84f065 100644 --- a/extensions/extension-editing/yarn.lock +++ b/extensions/extension-editing/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== "@types/node@^6.0.46": version "6.0.78" diff --git a/extensions/git-ui/.vscodeignore b/extensions/git-ui/.vscodeignore deleted file mode 100644 index 7462f7448d..0000000000 --- a/extensions/git-ui/.vscodeignore +++ /dev/null @@ -1,8 +0,0 @@ -src/** -test/** -out/** -tsconfig.json -build/** -extension.webpack.config.js -cgmanifest.json -yarn.lock diff --git a/extensions/git-ui/README.md b/extensions/git-ui/README.md deleted file mode 100644 index d418425acf..0000000000 --- a/extensions/git-ui/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# Git UI integration for Visual Studio Code - -**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled. - -## Features - -See [Git support in VS Code](https://code.visualstudio.com/docs/editor/versioncontrol#_git-support) to learn about the features of this extension. diff --git a/extensions/git-ui/cgmanifest.json b/extensions/git-ui/cgmanifest.json deleted file mode 100644 index f3071eb691..0000000000 --- a/extensions/git-ui/cgmanifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "registrations": [], - "version": 1 -} \ No newline at end of file diff --git a/extensions/git-ui/extension.webpack.config.js b/extensions/git-ui/extension.webpack.config.js deleted file mode 100644 index b63c59c65d..0000000000 --- a/extensions/git-ui/extension.webpack.config.js +++ /dev/null @@ -1,17 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -//@ts-check - -'use strict'; - -const withDefaults = require('../shared.webpack.config'); - -module.exports = withDefaults({ - context: __dirname, - entry: { - main: './src/main.ts' - } -}); diff --git a/extensions/git-ui/package.json b/extensions/git-ui/package.json deleted file mode 100644 index 2f1ab43f89..0000000000 --- a/extensions/git-ui/package.json +++ /dev/null @@ -1,28 +0,0 @@ -{ - "name": "git-ui", - "displayName": "%displayName%", - "description": "%description%", - "publisher": "vscode", - "version": "1.0.0", - "engines": { - "vscode": "^1.5.0" - }, - "extensionKind": "ui", - "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", - "enableProposedApi": true, - "categories": [ - "Other" - ], - "activationEvents": [ - "onCommand:git.credential" - ], - "main": "./out/main", - "icon": "resources/icons/git.png", - "scripts": { - "compile": "gulp compile-extension:git-ui", - "watch": "gulp watch-extension:git-ui" - }, - "devDependencies": { - "@types/node": "^10.14.8" - } -} \ No newline at end of file diff --git a/extensions/git-ui/package.nls.json b/extensions/git-ui/package.nls.json deleted file mode 100644 index 5303e91f4c..0000000000 --- a/extensions/git-ui/package.nls.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "displayName": "Git UI", - "description": "Git SCM UI Integration" -} \ No newline at end of file diff --git a/extensions/git-ui/resources/icons/git.png b/extensions/git-ui/resources/icons/git.png deleted file mode 100644 index 51f4ae5404..0000000000 Binary files a/extensions/git-ui/resources/icons/git.png and /dev/null differ diff --git a/extensions/git-ui/src/main.ts b/extensions/git-ui/src/main.ts deleted file mode 100644 index 057074fae6..0000000000 --- a/extensions/git-ui/src/main.ts +++ /dev/null @@ -1,57 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ExtensionContext, commands } from 'vscode'; - -import * as cp from 'child_process'; - -export async function deactivate(): Promise { -} - -export async function activate(context: ExtensionContext): Promise { - context.subscriptions.push(commands.registerCommand('git.credential', async (data: any) => { - try { - const { stdout, stderr } = await exec(`git credential ${data.command}`, { - stdin: data.stdin, - env: Object.assign(process.env, { GIT_TERMINAL_PROMPT: '0' }) - }); - return { stdout, stderr, code: 0 }; - } catch ({ stdout, stderr, error }) { - const code = error.code || 0; - if (stderr.indexOf('terminal prompts disabled') !== -1) { - stderr = ''; - } - return { stdout, stderr, code }; - } - })); -} - -export interface ExecResult { - error: Error | null; - stdout: string; - stderr: string; -} - - -export function exec(command: string, options: cp.ExecOptions & { stdin?: string } = {}) { - return new Promise((resolve, reject) => { - const child = cp.exec(command, options, (error, stdout, stderr) => { - (error ? reject : resolve)({ error, stdout, stderr }); - }); - if (options.stdin) { - child.stdin.write(options.stdin, (err: any) => { - if (err) { - reject(err); - return; - } - child.stdin.end((err: any) => { - if (err) { - reject(err); - } - }); - }); - } - }); -} diff --git a/extensions/git-ui/src/typings/refs.d.ts b/extensions/git-ui/src/typings/refs.d.ts deleted file mode 100644 index e28bb39716..0000000000 --- a/extensions/git-ui/src/typings/refs.d.ts +++ /dev/null @@ -1,8 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/// -/// -/// \ No newline at end of file diff --git a/extensions/git-ui/tsconfig.json b/extensions/git-ui/tsconfig.json deleted file mode 100644 index 27e9268b39..0000000000 --- a/extensions/git-ui/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../shared.tsconfig.json", - "compilerOptions": { - "outDir": "./out", - "experimentalDecorators": true, - "typeRoots": [ - "./node_modules/@types" - ] - }, - "include": [ - "src/**/*" - ] -} \ No newline at end of file diff --git a/extensions/git-ui/yarn.lock b/extensions/git-ui/yarn.lock deleted file mode 100644 index b23b0ac039..0000000000 --- a/extensions/git-ui/yarn.lock +++ /dev/null @@ -1,8 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== diff --git a/extensions/git/package.json b/extensions/git/package.json index 2debe889d3..a6cf112f69 100644 --- a/extensions/git/package.json +++ b/extensions/git/package.json @@ -3,7 +3,6 @@ "displayName": "%displayName%", "description": "%description%", "publisher": "vscode", - "license": "MIT", "version": "1.0.0", "engines": { "vscode": "^1.5.0" @@ -21,8 +20,7 @@ "scripts": { "compile": "gulp compile-extension:git", "watch": "gulp watch-extension:git", - "update-grammar": "node ./build/update-grammars.js", - "test": "mocha" + "update-grammar": "node ./build/update-grammars.js" }, "contributes": { "commands": [ @@ -1460,14 +1458,13 @@ "jschardet": "^1.6.0", "vscode-extension-telemetry": "0.1.1", "vscode-nls": "^4.0.0", - "vscode-uri": "^2.0.0", "which": "^1.3.0" }, "devDependencies": { "@types/byline": "4.2.31", "@types/file-type": "^5.2.1", "@types/mocha": "2.2.43", - "@types/node": "^10.14.8", + "@types/node": "^10.12.21", "@types/which": "^1.0.28", "mocha": "^3.2.0" } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 9e82d769f1..767aacd3c9 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -235,4 +235,4 @@ export const enum GitErrorCodes { CantRebaseMultipleBranches = 'CantRebaseMultipleBranches', PatchDoesNotApply = 'PatchDoesNotApply', NoPathFound = 'NoPathFound' -} +} \ No newline at end of file diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index ed912b8c44..e034c98593 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -56,13 +56,7 @@ class CheckoutRemoteHeadItem extends CheckoutItem { return; } - const branches = await repository.findTrackingBranches(this.ref.name); - - if (branches.length > 0) { - await repository.checkout(branches[0].name!); - } else { - await repository.checkoutTracking(this.ref.name); - } + await repository.checkoutTracking(this.ref.name); } } diff --git a/extensions/git/src/git.ts b/extensions/git/src/git.ts index d9d475bbf8..3684b30c5a 100644 --- a/extensions/git/src/git.ts +++ b/extensions/git/src/git.ts @@ -12,8 +12,7 @@ import { EventEmitter } from 'events'; import iconv = require('iconv-lite'); import * as filetype from 'file-type'; import { assign, groupBy, denodeify, IDisposable, toDisposable, dispose, mkdirp, readBytes, detectUnicodeEncoding, Encoding, onceEvent } from './util'; -import { CancellationToken } from 'vscode'; -import { URI } from 'vscode-uri'; +import { CancellationToken, Uri, workspace } from 'vscode'; import { detectEncoding } from './encoding'; import { Ref, RefType, Branch, Remote, GitErrorCodes, LogOptions, Change, Status } from './api/git'; @@ -558,7 +557,7 @@ export function parseGitmodules(raw: string): Submodule[] { return; } - const propertyMatch = /^\s*(\w+)\s+=\s+(.*)$/.exec(line); + const propertyMatch = /^\s*(\w+) = (.*)$/.exec(line); if (!propertyMatch) { return; @@ -637,7 +636,6 @@ export interface CommitOptions { export interface PullOptions { unshallow?: boolean; - tags?: boolean; } export enum ForcePushMode { @@ -997,7 +995,7 @@ export class Repository { break; } - const originalUri = URI.file(path.isAbsolute(resourcePath) ? resourcePath : path.join(this.repositoryRoot, resourcePath)); + const originalUri = Uri.file(path.isAbsolute(resourcePath) ? resourcePath : path.join(this.repositoryRoot, resourcePath)); let status: Status = Status.UNTRACKED; // Copy or Rename status comes with a number, e.g. 'R100'. We don't need the number, so we use only first character of the status. @@ -1025,7 +1023,7 @@ export class Repository { break; } - const uri = URI.file(path.isAbsolute(newPath) ? newPath : path.join(this.repositoryRoot, newPath)); + const uri = Uri.file(path.isAbsolute(newPath) ? newPath : path.join(this.repositoryRoot, newPath)); result.push({ uri, renameUri: uri, @@ -1365,8 +1363,9 @@ export class Repository { async pull(rebase?: boolean, remote?: string, branch?: string, options: PullOptions = {}): Promise { const args = ['pull']; + const config = workspace.getConfiguration('git', Uri.file(this.root)); - if (options.tags) { + if (config.get('pullTags')) { args.push('--tags'); } @@ -1579,14 +1578,6 @@ export class Repository { } } - async findTrackingBranches(upstreamBranch: string): Promise { - const result = await this.run(['for-each-ref', '--format', '%(refname:short)%00%(upstream:short)', 'refs/heads']); - return result.stdout.trim().split('\n') - .map(line => line.trim().split('\0')) - .filter(([_, upstream]) => upstream === upstreamBranch) - .map(([ref]) => ({ name: ref, type: RefType.Head } as Branch)); - } - async getRefs(): Promise { const result = await this.run(['for-each-ref', '--format', '%(refname) %(objectname)', '--sort', '-committerdate']); diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 125326535c..26888a11a2 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -299,7 +299,6 @@ export const enum Operation { GetObjectDetails = 'GetObjectDetails', SubmoduleUpdate = 'SubmoduleUpdate', RebaseContinue = 'RebaseContinue', - FindTrackingBranches = 'GetTracking', Apply = 'Apply', Blame = 'Blame', Log = 'Log', @@ -910,10 +909,6 @@ export class Repository implements Disposable { await this.run(Operation.CheckoutTracking, () => this.repository.checkout(treeish, [], { track: true })); } - async findTrackingBranches(upstreamRef: string): Promise { - return await this.run(Operation.FindTrackingBranches, () => this.repository.findTrackingBranches(upstreamRef)); - } - async getCommit(ref: string): Promise { return await this.repository.getCommit(ref); } @@ -984,12 +979,11 @@ export class Repository implements Disposable { await this.maybeAutoStash(async () => { const config = workspace.getConfiguration('git', Uri.file(this.root)); const fetchOnPull = config.get('fetchOnPull'); - const tags = config.get('pullTags'); if (fetchOnPull) { - await this.repository.pull(rebase, undefined, undefined, { unshallow, tags }); + await this.repository.pull(rebase, undefined, undefined, { unshallow }); } else { - await this.repository.pull(rebase, remote, branch, { unshallow, tags }); + await this.repository.pull(rebase, remote, branch, { unshallow }); } }); }); @@ -1045,12 +1039,11 @@ export class Repository implements Disposable { await this.maybeAutoStash(async () => { const config = workspace.getConfiguration('git', Uri.file(this.root)); const fetchOnPull = config.get('fetchOnPull'); - const tags = config.get('pullTags'); if (fetchOnPull) { - await this.repository.pull(rebase, undefined, undefined, { tags }); + await this.repository.pull(rebase); } else { - await this.repository.pull(rebase, remoteName, pullBranch, { tags }); + await this.repository.pull(rebase, remoteName, pullBranch); } const remote = this.remotes.find(r => r.name === remoteName); @@ -1163,7 +1156,7 @@ export class Repository implements Disposable { } // https://git-scm.com/docs/git-check-ignore#git-check-ignore--z - const child = this.repository.stream(['check-ignore', '-v', '-z', '--stdin'], { stdio: [null, null, null] }); + const child = this.repository.stream(['check-ignore', '-z', '--stdin'], { stdio: [null, null, null] }); child.stdin.end(filePaths.join('\0'), 'utf8'); const onExit = (exitCode: number) => { @@ -1171,7 +1164,8 @@ export class Repository implements Disposable { // nothing ignored resolve(new Set()); } else if (exitCode === 0) { - resolve(new Set(this.parseIgnoreCheck(data))); + // paths are separated by the null-character + resolve(new Set(data.split('\0'))); } else { if (/ is in submodule /.test(stderr)) { reject(new GitError({ stdout: data, stderr, exitCode, gitErrorCode: GitErrorCodes.IsInSubmodule })); @@ -1199,23 +1193,6 @@ export class Repository implements Disposable { }); } - // Parses output of `git check-ignore -v -z` and returns only those paths - // that are actually ignored by git. - // Matches to a negative pattern (starting with '!') are filtered out. - // See also https://git-scm.com/docs/git-check-ignore#_output. - private parseIgnoreCheck(raw: string): string[] { - const ignored = []; - const elements = raw.split('\0'); - for (let i = 0; i < elements.length; i += 4) { - const pattern = elements[i + 2]; - const path = elements[i + 3]; - if (pattern && !pattern.startsWith('!')) { - ignored.push(path); - } - } - return ignored; - } - private async run(operation: Operation, runOperation: () => Promise = () => Promise.resolve(null)): Promise { if (this.state !== RepositoryState.Idle) { throw new Error('Repository not initialized'); diff --git a/extensions/git/src/test/git.test.ts b/extensions/git/src/test/git.test.ts index facabe3550..8e27a374fa 100644 --- a/extensions/git/src/test/git.test.ts +++ b/extensions/git/src/test/git.test.ts @@ -172,17 +172,6 @@ suite('git', () => { { name: 'deps/spdlog4', path: 'deps/spdlog4', url: 'https://github.com/gabime/spdlog4.git' } ]); }); - - test('whitespace #74844', () => { - const sample = `[submodule "deps/spdlog"] - path = deps/spdlog - url = https://github.com/gabime/spdlog.git -`; - - assert.deepEqual(parseGitmodules(sample), [ - { name: 'deps/spdlog', path: 'deps/spdlog', url: 'https://github.com/gabime/spdlog.git' } - ]); - }); }); suite('parseGitCommit', () => { diff --git a/extensions/git/yarn.lock b/extensions/git/yarn.lock index 1f2ea8aed4..f13ef93c34 100644 --- a/extensions/git/yarn.lock +++ b/extensions/git/yarn.lock @@ -26,10 +26,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== "@types/which@^1.0.28": version "1.0.28" @@ -325,11 +325,6 @@ vscode-nls@^4.0.0: resolved "https://registry.yarnpkg.com/vscode-nls/-/vscode-nls-4.0.0.tgz#4001c8a6caba5cedb23a9c5ce1090395c0e44002" integrity sha512-qCfdzcH+0LgQnBpZA53bA32kzp9rpq/f66Som577ObeuDlFIrtbEJ+A/+CCxjIh4G8dpJYNCKIsxpRAHIfsbNw== -vscode-uri@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.0.tgz#2df704222f72b8a71ff266ba0830ed6c51ac1542" - integrity sha512-lWXWofDSYD8r/TIyu64MdwB4FaSirQ608PP/TzUyslyOeHGwQ0eTHUZeJrK1ILOmwUHaJtV693m2JoUYroUDpw== - which@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/which/-/which-1.3.0.tgz#ff04bdfc010ee547d780bec38e1ac1c2777d253a" diff --git a/extensions/json-language-features/package.json b/extensions/json-language-features/package.json index 0847ae5e08..9dc4f87d9f 100644 --- a/extensions/json-language-features/package.json +++ b/extensions/json-language-features/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "0.10.x" @@ -108,6 +107,6 @@ "request-light": "^0.2.4" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "^10.12.21" } } diff --git a/extensions/json-language-features/server/README.md b/extensions/json-language-features/server/README.md index 9b02dc24ef..27be5ab1bb 100644 --- a/extensions/json-language-features/server/README.md +++ b/extensions/json-language-features/server/README.md @@ -154,8 +154,7 @@ To connect to the server from NodeJS, see Remy Suen's great write-up on [how to ## Participate -The source code of the JSON language server can be found in the [VSCode repository](https://github.com/Microsoft/vscode) at [extensions/json-language-features/server](https://github.com/Microsoft/vscode/tree/master/extensions/json-language-features/server). - +The source code of the JSON language server can be found [VSCode repository](https://github.com/Microsoft/vscode) at [extensions/json-language-features/server](https://github.com/Microsoft/vscode/tree/master/extensions/json-language-features/server). File issues and pull requests in the [VSCode GitHub Issues](https://github.com/Microsoft/vscode/issues). See the document [How to Contribute](https://github.com/Microsoft/vscode/wiki/How-to-Contribute) on how to build and run from source. Most of the functionality of the server is located in libraries: @@ -165,12 +164,10 @@ Most of the functionality of the server is located in libraries: Help on any of these projects is very welcome. -## Code of Conduct - -This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +Please see also our [Code of Conduct](CODE_OF_CONDUCT.md). ## License Copyright (c) Microsoft Corporation. All rights reserved. -Licensed under the [MIT](https://github.com/microsoft/vscode/blob/master/LICENSE.txt) License. +Licensed under the [MIT](LICENSE.txt) License. diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 054c0fe017..1f73cea229 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -21,7 +21,7 @@ }, "devDependencies": { "@types/mocha": "2.2.33", - "@types/node": "^10.14.8" + "@types/node": "^10.12.21" }, "scripts": { "prepublishOnly": "npm run clean && npm run test", diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index c7e54ce884..3f0383a8c4 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -7,10 +7,10 @@ resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.33.tgz#d79a0061ec270379f4d9e225f4096fb436669def" integrity sha1-15oAYewnA3n02eIl9AlvtDZmne8= -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== agent-base@4, agent-base@^4.1.0: version "4.1.2" diff --git a/extensions/json-language-features/yarn.lock b/extensions/json-language-features/yarn.lock index 0f11fa9d58..758f96fd51 100644 --- a/extensions/json-language-features/yarn.lock +++ b/extensions/json-language-features/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== agent-base@4, agent-base@^4.1.0: version "4.2.1" diff --git a/extensions/json/package.json b/extensions/json/package.json index 9c8b0f84a2..fd0dd54ff2 100644 --- a/extensions/json/package.json +++ b/extensions/json/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "0.10.x" }, diff --git a/extensions/markdown-basics/package.json b/extensions/markdown-basics/package.json index 26a3599cf5..8d1ef2828c 100644 --- a/extensions/markdown-basics/package.json +++ b/extensions/markdown-basics/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "^1.20.0" }, diff --git a/extensions/markdown-language-features/media/markdown.css b/extensions/markdown-language-features/media/markdown.css index f1da84d9dc..1be3a3fa03 100644 --- a/extensions/markdown-language-features/media/markdown.css +++ b/extensions/markdown-language-features/media/markdown.css @@ -135,6 +135,7 @@ h3 code, h4 code, h5 code, h6 code { + font-size: inherit; line-height: auto; } @@ -167,8 +168,8 @@ blockquote { code { font-family: Menlo, Monaco, Consolas, "Droid Sans Mono", "Courier New", monospace, "Droid Sans Fallback"; - font-size: 1em; - line-height: 1.357em; + font-size: 1rem; + line-height: 1.357rem; } body.wordWrap pre { diff --git a/extensions/markdown-language-features/package.json b/extensions/markdown-language-features/package.json index dc82280c4e..e18099fe67 100644 --- a/extensions/markdown-language-features/package.json +++ b/extensions/markdown-language-features/package.json @@ -5,7 +5,6 @@ "version": "1.0.0", "icon": "icon.png", "publisher": "vscode", - "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "^1.20.0" @@ -314,7 +313,7 @@ "build-preview": "webpack --mode development" }, "dependencies": { - "highlight.js": "9.15.8", + "highlight.js": "9.13.1", "markdown-it": "^8.4.2", "markdown-it-front-matter": "^0.1.2", "vscode-extension-telemetry": "0.1.1", @@ -324,7 +323,7 @@ "@types/highlight.js": "9.12.3", "@types/lodash.throttle": "^4.1.3", "@types/markdown-it": "0.0.2", - "@types/node": "^10.14.8", + "@types/node": "^10.12.21", "lodash.throttle": "^4.1.1", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", diff --git a/extensions/markdown-language-features/src/features/documentLinkProvider.ts b/extensions/markdown-language-features/src/features/documentLinkProvider.ts index 970cea3d89..a41e4adc7f 100644 --- a/extensions/markdown-language-features/src/features/documentLinkProvider.ts +++ b/extensions/markdown-language-features/src/features/documentLinkProvider.ts @@ -5,20 +5,17 @@ import * as path from 'path'; import * as vscode from 'vscode'; -import * as nls from 'vscode-nls'; import { OpenDocumentLinkCommand } from '../commands/openDocumentLink'; import { getUriForLinkWithKnownExternalScheme } from '../util/links'; -const localize = nls.loadMessageBundle(); - -function parseLink( +function normalizeLink( document: vscode.TextDocument, link: string, base: string -): { uri: vscode.Uri, tooltip?: string } { +): vscode.Uri { const externalSchemeUri = getUriForLinkWithKnownExternalScheme(link); if (externalSchemeUri) { - return { uri: externalSchemeUri }; + return externalSchemeUri; } // Assume it must be an relative or absolute file path @@ -37,10 +34,7 @@ function parseLink( resourcePath = base ? path.join(base, tempUri.path) : tempUri.path; } - return { - uri: OpenDocumentLinkCommand.createCommandUri(resourcePath, tempUri.fragment), - tooltip: localize('documentLink.tooltip', 'follow link') - }; + return OpenDocumentLinkCommand.createCommandUri(resourcePath, tempUri.fragment); } function matchAll( @@ -67,12 +61,9 @@ function extractDocumentLink( const linkStart = document.positionAt(offset); const linkEnd = document.positionAt(offset + link.length); try { - const { uri, tooltip } = parseLink(document, link, base); - const documentLink = new vscode.DocumentLink( + return new vscode.DocumentLink( new vscode.Range(linkStart, linkEnd), - uri); - documentLink.tooltip = tooltip; - return documentLink; + normalizeLink(document, link, base)); } catch (e) { return undefined; } @@ -153,10 +144,11 @@ export default class LinkProvider implements vscode.DocumentLinkProvider { } } - for (const definition of definitions.values()) { + for (const definition of Array.from(definitions.values())) { try { - const { uri } = parseLink(document, definition.link, base); - results.push(new vscode.DocumentLink(definition.linkRange, uri)); + results.push(new vscode.DocumentLink( + definition.linkRange, + normalizeLink(document, definition.link, base))); } catch (e) { // noop } diff --git a/extensions/markdown-language-features/yarn.lock b/extensions/markdown-language-features/yarn.lock index a1b876e7dc..e85ae950b3 100644 --- a/extensions/markdown-language-features/yarn.lock +++ b/extensions/markdown-language-features/yarn.lock @@ -29,10 +29,10 @@ resolved "https://registry.yarnpkg.com/@types/markdown-it/-/markdown-it-0.0.2.tgz#5d9ad19e6e6508cdd2f2596df86fd0aade598660" integrity sha1-XZrRnm5lCM3S8llt+G/Qqt5ZhmA= -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== abbrev@1: version "1.1.1" @@ -2933,10 +2933,10 @@ he@1.1.1: resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0= -highlight.js@9.15.8: - version "9.15.8" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.15.8.tgz#f344fda123f36f1a65490e932cf90569e4999971" - integrity sha512-RrapkKQWwE+wKdF73VsOa2RQdIoO3mxwJ4P8mhbI6KYJUraUHRKM5w5zQQKXNk0xNL4UVRdulV9SBJcmzJNzVA== +highlight.js@9.13.1: + version "9.13.1" + resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e" + integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A== hmac-drbg@^1.0.0: version "1.0.1" diff --git a/extensions/merge-conflict/package.json b/extensions/merge-conflict/package.json index 2828669b04..efc0ff0cf7 100644 --- a/extensions/merge-conflict/package.json +++ b/extensions/merge-conflict/package.json @@ -5,7 +5,6 @@ "description": "%description%", "icon": "resources/icons/merge-conflict.png", "version": "1.0.0", - "license": "MIT", "aiKey": "AIF-d9b70cd4-b9f9-4d70-929b-a071c400b217", "engines": { "vscode": "^1.5.0" @@ -115,21 +114,6 @@ "type": "boolean", "description": "%config.autoNavigateNextConflictEnabled%", "default": false - }, - "merge-conflict.diffViewPosition": { - "type": "string", - "enum": [ - "Current", - "Beside", - "Below" - ], - "description": "%config.diffViewPosition%", - "enumDescriptions": [ - "%config.diffViewPosition.current%", - "%config.diffViewPosition.beside%", - "%config.diffViewPosition.below%" - ], - "default": "Current" } } } @@ -138,6 +122,6 @@ "vscode-nls": "^4.0.0" }, "devDependencies": { - "@types/node": "^10.14.8" + "@types/node": "8.0.33" } } diff --git a/extensions/merge-conflict/package.nls.json b/extensions/merge-conflict/package.nls.json index 3310dac7e2..94599bf281 100644 --- a/extensions/merge-conflict/package.nls.json +++ b/extensions/merge-conflict/package.nls.json @@ -15,9 +15,5 @@ "config.title": "Merge Conflict", "config.autoNavigateNextConflictEnabled": "Whether to automatically navigate to the next merge conflict after resolving a merge conflict.", "config.codeLensEnabled": "Create a Code Lens for merge conflict blocks within editor.", - "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor.", - "config.diffViewPosition": "Controls where the diff view should be opened when comparing changes in merge conflicts.", - "config.diffViewPosition.current": "Open the diff view in the current editor group.", - "config.diffViewPosition.beside": "Open the diff view next to the current editor group.", - "config.diffViewPosition.below": "Open the diff view below the current editor group." + "config.decoratorsEnabled": "Create decorators for merge conflict blocks within editor." } \ No newline at end of file diff --git a/extensions/merge-conflict/src/commandHandler.ts b/extensions/merge-conflict/src/commandHandler.ts index 7f6630c09e..5807223e4e 100644 --- a/extensions/merge-conflict/src/commandHandler.ts +++ b/extensions/merge-conflict/src/commandHandler.ts @@ -88,54 +88,18 @@ export default class CommandHandler implements vscode.Disposable { } } - const conflicts = await this.tracker.getConflicts(editor.document); - - // Still failed to find conflict, warn the user and exit - if (!conflicts) { - vscode.window.showWarningMessage(localize('cursorNotInConflict', 'Editor cursor is not within a merge conflict')); - return; - } - const scheme = editor.document.uri.scheme; let range = conflict.current.content; - let leftRanges = conflicts.map(conflict => [conflict.current.content, conflict.range]); - let rightRanges = conflicts.map(conflict => [conflict.incoming.content, conflict.range]); - const leftUri = editor.document.uri.with({ scheme: ContentProvider.scheme, - query: JSON.stringify({ scheme, range: range, ranges: leftRanges }) + query: JSON.stringify({ scheme, range }) }); - range = conflict.incoming.content; - const rightUri = leftUri.with({ query: JSON.stringify({ scheme, ranges: rightRanges }) }); - - let mergeConflictLineOffsets = 0; - for (let nextconflict of conflicts) { - if (nextconflict.range.isEqual(conflict.range)) { - break; - } else { - mergeConflictLineOffsets += (nextconflict.range.end.line - nextconflict.range.start.line) - (nextconflict.incoming.content.end.line - nextconflict.incoming.content.start.line); - } - } - const selection = new vscode.Range( - conflict.range.start.line - mergeConflictLineOffsets, conflict.range.start.character, - conflict.range.start.line - mergeConflictLineOffsets, conflict.range.start.character - ); + const rightUri = leftUri.with({ query: JSON.stringify({ scheme, range }) }); const title = localize('compareChangesTitle', '{0}: Current Changes ⟷ Incoming Changes', fileName); - const mergeConflictConfig = vscode.workspace.getConfiguration('merge-conflict'); - const openToTheSide = mergeConflictConfig.get('diffViewPosition'); - const opts: vscode.TextDocumentShowOptions = { - viewColumn: openToTheSide === 'Beside' ? vscode.ViewColumn.Beside : vscode.ViewColumn.Active, - selection - }; - - if (openToTheSide === 'Below') { - await vscode.commands.executeCommand('workbench.action.newGroupBelow'); - } - - await vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title, opts); + vscode.commands.executeCommand('vscode.diff', leftUri, rightUri, title); } navigateNext(editor: vscode.TextEditor): Promise { diff --git a/extensions/merge-conflict/src/contentProvider.ts b/extensions/merge-conflict/src/contentProvider.ts index 49bbf0aa94..542a9ccc02 100644 --- a/extensions/merge-conflict/src/contentProvider.ts +++ b/extensions/merge-conflict/src/contentProvider.ts @@ -23,27 +23,11 @@ export default class MergeConflictContentProvider implements vscode.TextDocument async provideTextDocumentContent(uri: vscode.Uri): Promise { try { - const { scheme, ranges } = JSON.parse(uri.query) as { scheme: string, ranges: [{ line: number, character: number }[], { line: number, character: number }[]][] }; + const { scheme, range } = JSON.parse(uri.query) as { scheme: string; range: { line: number, character: number }[] }; + const [start, end] = range; - // complete diff const document = await vscode.workspace.openTextDocument(uri.with({ scheme, query: '' })); - - let text = ''; - let lastPosition = new vscode.Position(0, 0); - - ranges.forEach(rangeObj => { - let [conflictRange, fullRange] = rangeObj; - const [start, end] = conflictRange; - const [fullStart, fullEnd] = fullRange; - - text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, fullStart.line, fullStart.character)); - text += document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); - lastPosition = new vscode.Position(fullEnd.line, fullEnd.character); - }); - - let documentEnd = document.lineAt(document.lineCount - 1).range.end; - text += document.getText(new vscode.Range(lastPosition.line, lastPosition.character, documentEnd.line, documentEnd.character)); - + const text = document.getText(new vscode.Range(start.line, start.character, end.line, end.character)); return text; } catch (ex) { diff --git a/extensions/merge-conflict/yarn.lock b/extensions/merge-conflict/yarn.lock index e6247e2925..6767cb8d8c 100644 --- a/extensions/merge-conflict/yarn.lock +++ b/extensions/merge-conflict/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@8.0.33": + version "8.0.33" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" + integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== vscode-nls@^4.0.0: version "4.0.0" diff --git a/extensions/objective-c/build/update-grammars.js b/extensions/objective-c/build/update-grammars.js deleted file mode 100644 index 2c9b27a4e9..0000000000 --- a/extensions/objective-c/build/update-grammars.js +++ /dev/null @@ -1,11 +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'; - -var updateGrammar = require('../../../build/npm/update-grammar'); - -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/objc.tmLanguage.json', './syntaxes/objective-c.tmLanguage.json'); -updateGrammar.update('jeff-hykin/cpp-textmate-grammar', '/syntaxes/objcpp.tmLanguage.json', './syntaxes/objective-c++.tmLanguage.json'); - diff --git a/extensions/objective-c/test/colorize-fixtures/test.mm b/extensions/objective-c/test/colorize-fixtures/test.mm deleted file mode 100644 index d5d31433ae..0000000000 --- a/extensions/objective-c/test/colorize-fixtures/test.mm +++ /dev/null @@ -1,52 +0,0 @@ -// -// Copyright (c) Microsoft Corporation. All rights reserved. -// - -#import "UseQuotes.h" -#import - -/* - Multi - Line - Comments -*/ -@implementation Test - -- (void) applicationWillFinishLaunching:(NSNotification *)notification -{ -} - -- (IBAction)onSelectInput:(id)sender -{ - NSString* defaultDir = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true)[0]; - - NSOpenPanel* panel = [NSOpenPanel openPanel]; - [panel setAllowedFileTypes:[[NSArray alloc] initWithObjects:@"ipa", @"xcarchive", @"app", nil]]; - - [panel beginWithCompletionHandler:^(NSInteger result) - { - if (result == NSFileHandlingPanelOKButton) - [self.inputTextField setStringValue:[panel.URL path]]; - }]; - return YES; - - int hex = 0xFEF1F0F; - float ing = 3.14; - ing = 3.14e0; - ing = 31.4e-2; -} - --(id) initWithParams:(id) aHandler withDeviceStateManager:(id) deviceStateManager -{ - // add a tap gesture recognizer - UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleTap:)]; - NSMutableArray *gestureRecognizers = [NSMutableArray array]; - [gestureRecognizers addObject:tapGesture]; - [gestureRecognizers addObjectsFromArray:scnView.gestureRecognizers]; - scnView.gestureRecognizers = gestureRecognizers; - - return tapGesture; - return nil; -} - -@end diff --git a/extensions/objective-c/test/colorize-results/test_mm.json b/extensions/objective-c/test/colorize-results/test_mm.json deleted file mode 100644 index 2af2751bce..0000000000 --- a/extensions/objective-c/test/colorize-results/test_mm.json +++ /dev/null @@ -1,3093 +0,0 @@ -[ - { - "c": "//", - "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "//", - "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " Copyright (c) Microsoft Corporation. All rights reserved.", - "t": "source.objcpp comment.line.double-slash.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "//", - "t": "source.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "#", - "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp punctuation.definition.directive.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": "import", - "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.preprocessor.include.objcpp", - "r": { - "dark_plus": "meta.preprocessor: #569CD6", - "light_plus": "meta.preprocessor: #0000FF", - "dark_vs": "meta.preprocessor: #569CD6", - "light_vs": "meta.preprocessor: #0000FF", - "hc_black": "meta.preprocessor: #569CD6" - } - }, - { - "c": "\"", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp punctuation.definition.string.begin.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "UseQuotes.h", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "\"", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.double.include.objcpp punctuation.definition.string.end.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "#", - "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp punctuation.definition.directive.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": "import", - "t": "source.objcpp meta.preprocessor.include.objcpp keyword.control.directive.import.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.preprocessor.include.objcpp", - "r": { - "dark_plus": "meta.preprocessor: #569CD6", - "light_plus": "meta.preprocessor: #0000FF", - "dark_vs": "meta.preprocessor: #569CD6", - "light_vs": "meta.preprocessor: #0000FF", - "hc_black": "meta.preprocessor: #569CD6" - } - }, - { - "c": "<", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp punctuation.definition.string.begin.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "Use/GTLT.h", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": ">", - "t": "source.objcpp meta.preprocessor.include.objcpp string.quoted.other.lt-gt.include.objcpp punctuation.definition.string.end.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "/*", - "t": "source.objcpp comment.block.objcpp punctuation.definition.comment.begin.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "\tMulti", - "t": "source.objcpp comment.block.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "\tLine", - "t": "source.objcpp comment.block.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "\tComments", - "t": "source.objcpp comment.block.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "*/", - "t": "source.objcpp comment.block.objcpp punctuation.definition.comment.end.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": "@", - "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "implementation", - "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "Test", - "t": "source.objcpp meta.implementation.objcpp entity.name.type.objcpp", - "r": { - "dark_plus": "entity.name.type: #4EC9B0", - "light_plus": "entity.name.type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.type: #4EC9B0" - } - }, - { - "c": "- ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "void", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.built-in.primitive.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "applicationWillFinishLaunching", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": ":", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSNotification", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "*", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "notification", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": "{", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "}", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "- ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "IBAction", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "onSelectInput", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": ":", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "id", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp storage.type.id.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "sender", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": "{", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSString", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": "*", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " defaultDir ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.whitespace.support.function.leading.cocoa.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSSearchPathForDirectoriesInDomains", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.function.cocoa.objcpp", - "r": { - "dark_plus": "support.function: #DCDCAA", - "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.function: #DCDCAA" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.section.parens.begin.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSDocumentDirectory", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ",", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.separator.delimiter.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSUserDomainMask", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ",", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.separator.delimiter.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "true", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp constant.language.objcpp", - "r": { - "dark_plus": "constant.language: #569CD6", - "light_plus": "constant.language: #0000FF", - "dark_vs": "constant.language: #569CD6", - "light_vs": "constant.language: #0000FF", - "hc_black": "constant.language: #569CD6" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.parens.block.objcpp punctuation.section.parens.end.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "0", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSOpenPanel", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": "*", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " panel ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSOpenPanel", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": " openPanel", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "panel setAllowedFileTypes:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSArray", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": " alloc", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " initWithObjects:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "@\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "ipa", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": ",", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "@\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "xcarchive", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": ",", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "@\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.begin.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "app", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": "\"", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp string.quoted.double.objcpp punctuation.definition.string.end.objcpp", - "r": { - "dark_plus": "string: #CE9178", - "light_plus": "string: #A31515", - "dark_vs": "string: #CE9178", - "light_vs": "string: #A31515", - "hc_black": "string: #CE9178" - } - }, - { - "c": ",", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.delimiter.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "nil", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp constant.language.objcpp", - "r": { - "dark_plus": "constant.language: #569CD6", - "light_plus": "constant.language: #0000FF", - "dark_vs": "constant.language: #569CD6", - "light_vs": "constant.language: #0000FF", - "hc_black": "constant.language: #569CD6" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "panel beginWithCompletionHandler:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "^", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.parens.begin.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSInteger", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.type.cocoa.leopard.objcpp", - "r": { - "dark_plus": "support.type: #4EC9B0", - "light_plus": "support.type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.type: #4EC9B0" - } - }, - { - "c": " result", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.parens.end.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "{", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.block.begin.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "if", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp keyword.control.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp punctuation.section.parens.begin.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "result ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "==", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp keyword.operator.comparison.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSFileHandlingPanelOKButton", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp support.constant.cocoa.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.parens.block.objcpp punctuation.section.parens.end.bracket.round.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "self", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "inputTextField", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " setStringValue:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "panel", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "URL", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " path", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "}", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.section.block.end.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "return", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "YES", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.language.objcpp", - "r": { - "dark_plus": "constant.language: #569CD6", - "light_plus": "constant.language: #0000FF", - "dark_vs": "constant.language: #569CD6", - "light_vs": "constant.language: #0000FF", - "hc_black": "constant.language: #569CD6" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "int", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp storage.type.built-in.primitive.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " hex ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "0x", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.hexadecimal.objcpp", - "r": { - "dark_plus": "keyword.other.unit: #B5CEA8", - "light_plus": "keyword.other.unit: #09885A", - "dark_vs": "keyword.other.unit: #B5CEA8", - "light_vs": "keyword.other.unit: #09885A", - "hc_black": "keyword.other.unit: #B5CEA8" - } - }, - { - "c": "FEF1F0F", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.hexadecimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "\t ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "float", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp storage.type.built-in.primitive.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": " ing ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "3", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "14", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "\t ing ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "3", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "14", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "e", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.exponent.decimal.objcpp", - "r": { - "dark_plus": "keyword.other.unit: #B5CEA8", - "light_plus": "keyword.other.unit: #09885A", - "dark_vs": "keyword.other.unit: #B5CEA8", - "light_vs": "keyword.other.unit: #09885A", - "hc_black": "keyword.other.unit: #B5CEA8" - } - }, - { - "c": "0", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.exponent.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "\t ing ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "31", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.point.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "4", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": "e", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.other.unit.exponent.decimal.objcpp", - "r": { - "dark_plus": "keyword.other.unit: #B5CEA8", - "light_plus": "keyword.other.unit: #09885A", - "dark_vs": "keyword.other.unit: #B5CEA8", - "light_vs": "keyword.other.unit: #09885A", - "hc_black": "keyword.other.unit: #B5CEA8" - } - }, - { - "c": "-", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.minus.exponent.decimal.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": "2", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.numeric.exponent.decimal.objcpp", - "r": { - "dark_plus": "constant.numeric: #B5CEA8", - "light_plus": "constant.numeric: #09885A", - "dark_vs": "constant.numeric: #B5CEA8", - "light_vs": "constant.numeric: #09885A", - "hc_black": "constant.numeric: #B5CEA8" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "}", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "-", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "id", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp storage.type.id.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp", - "r": { - "dark_plus": "meta.return-type: #4EC9B0", - "light_plus": "meta.return-type: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "meta.return-type: #4EC9B0" - } - }, - { - "c": "initWithParams", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.return-type.objcpp entity.name.function.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": ":", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "id", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "<", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "anObject", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ">", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "aHandler", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "withDeviceStateManager", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp entity.name.function.name-of-parameter.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": ":", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp entity.name.function.name-of-parameter.objcpp punctuation.separator.arguments.objcpp", - "r": { - "dark_plus": "entity.name.function: #DCDCAA", - "light_plus": "entity.name.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "entity.name.function: #DCDCAA" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "id", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "<", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.begin.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "anotherObject", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ">", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp meta.id-with-protocol.objcpp meta.protocol-list.objcpp punctuation.section.scope.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp punctuation.definition.type.end.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "deviceStateManager", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.function.objcpp meta.argument-type.objcpp variable.parameter.function.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": "{", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.begin.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.whitespace.comment.leading.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "//", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp comment.line.double-slash.objcpp punctuation.definition.comment.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " add a tap gesture recognizer", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp comment.line.double-slash.objcpp", - "r": { - "dark_plus": "comment: #6A9955", - "light_plus": "comment: #008000", - "dark_vs": "comment: #6A9955", - "light_vs": "comment: #008000", - "hc_black": "comment: #7CA668" - } - }, - { - "c": " UITapGestureRecognizer ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "*", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": "tapGesture ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "UITapGestureRecognizer alloc", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " initWithTarget:self action:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "@", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "selector", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "(", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp punctuation.definition.storage.type.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "handleTap:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp meta.selector.method-name.objcpp support.function.any-method.name-of-parameter.objcpp", - "r": { - "dark_plus": "support.function: #DCDCAA", - "light_plus": "support.function: #795E26", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.function: #DCDCAA" - } - }, - { - "c": ")", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp meta.selector.objcpp punctuation.definition.storage.type.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSMutableArray", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "*", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": "gestureRecognizers ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "NSMutableArray", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp support.class.cocoa.objcpp", - "r": { - "dark_plus": "support.class: #4EC9B0", - "light_plus": "support.class: #267F99", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "support.class: #4EC9B0" - } - }, - { - "c": " array", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "gestureRecognizers addObject:tapGesture", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "[", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.begin.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "gestureRecognizers addObjectsFromArray:", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "scnView", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp variable.other.object.access.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.separator.dot-access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "gestureRecognizers", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp variable.other.member.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": "]", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp meta.bracket.square.access.objcpp punctuation.definition.end.bracket.square.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "scnView", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp variable.other.object.access.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": ".", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.separator.dot-access.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "gestureRecognizers", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp variable.other.member.objcpp", - "r": { - "dark_plus": "variable: #9CDCFE", - "light_plus": "variable: #001080", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "variable: #9CDCFE" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "=", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.operator.assignment.objcpp", - "r": { - "dark_plus": "keyword.operator: #D4D4D4", - "light_plus": "keyword.operator: #000000", - "dark_vs": "keyword.operator: #D4D4D4", - "light_vs": "keyword.operator: #000000", - "hc_black": "keyword.operator: #D4D4D4" - } - }, - { - "c": " gestureRecognizers", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "\t", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "return", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " tapGesture", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "\t", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "return", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp keyword.control.objcpp", - "r": { - "dark_plus": "keyword.control: #C586C0", - "light_plus": "keyword.control: #AF00DB", - "dark_vs": "keyword.control: #569CD6", - "light_vs": "keyword.control: #0000FF", - "hc_black": "keyword.control: #C586C0" - } - }, - { - "c": " ", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "nil", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp constant.language.objcpp", - "r": { - "dark_plus": "constant.language: #569CD6", - "light_plus": "constant.language: #0000FF", - "dark_vs": "constant.language: #569CD6", - "light_vs": "constant.language: #0000FF", - "hc_black": "constant.language: #569CD6" - } - }, - { - "c": ";", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.terminator.statement.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "}", - "t": "source.objcpp meta.implementation.objcpp meta.scope.implementation.objcpp meta.function-with-body.objcpp meta.block.objcpp punctuation.section.block.end.bracket.curly.objcpp", - "r": { - "dark_plus": "default: #D4D4D4", - "light_plus": "default: #000000", - "dark_vs": "default: #D4D4D4", - "light_vs": "default: #000000", - "hc_black": "default: #FFFFFF" - } - }, - { - "c": "@", - "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp punctuation.definition.storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - }, - { - "c": "end", - "t": "source.objcpp meta.implementation.objcpp storage.type.objcpp", - "r": { - "dark_plus": "storage.type: #569CD6", - "light_plus": "storage.type: #0000FF", - "dark_vs": "storage.type: #569CD6", - "light_vs": "storage.type: #0000FF", - "hc_black": "storage.type: #569CD6" - } - } -] \ No newline at end of file diff --git a/extensions/package.json b/extensions/package.json index b397a2d852..2615d1efa9 100644 --- a/extensions/package.json +++ b/extensions/package.json @@ -3,7 +3,7 @@ "version": "0.0.1", "description": "Dependencies shared by all extensions", "dependencies": { - "typescript": "3.5.1" + "typescript": "3.5.0-dev.20190522" }, "scripts": { "postinstall": "node ./postinstall" diff --git a/extensions/powershell/package.json b/extensions/powershell/package.json index 232acb1a7d..399f6fc560 100644 --- a/extensions/powershell/package.json +++ b/extensions/powershell/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "languages": [{ diff --git a/extensions/python/package.json b/extensions/python/package.json index 1553bad319..53ca25bd88 100644 --- a/extensions/python/package.json +++ b/extensions/python/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "activationEvents": ["onLanguage:python"], "main": "./out/pythonMain", @@ -13,7 +12,6 @@ "id": "python", "extensions": [ ".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi", ".snakefile", ".smk", ".pyi", ".ipy"], "aliases": [ "Python", "py" ], - "filenames": [ "Snakefile" ], "firstLine": "^#!\\s*/.*\\bpython[0-9.-]*\\b", "configuration": "./language-configuration.json" }], diff --git a/extensions/r/package.json b/extensions/r/package.json index 63ff6a6dcb..c9b682918b 100644 --- a/extensions/r/package.json +++ b/extensions/r/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js Ikuyadeu/vscode-R syntax/r.json ./syntaxes/r.tmLanguage.json" diff --git a/extensions/sql/package.json b/extensions/sql/package.json index 8c283e9724..f0256026d4 100644 --- a/extensions/sql/package.json +++ b/extensions/sql/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "scripts": { "update-grammar": "node ../../build/npm/update-grammar.js Microsoft/vscode-mssql syntaxes/SQL.plist ./syntaxes/sql.tmLanguage.json" diff --git a/extensions/theme-abyss/package.json b/extensions/theme-abyss/package.json index bdeb6a2a64..2d6e6962c2 100644 --- a/extensions/theme-abyss/package.json +++ b/extensions/theme-abyss/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-abyss/themes/abyss-color-theme.json b/extensions/theme-abyss/themes/abyss-color-theme.json index 43a3ae648d..1f7d48782d 100644 --- a/extensions/theme-abyss/themes/abyss-color-theme.json +++ b/extensions/theme-abyss/themes/abyss-color-theme.json @@ -86,9 +86,7 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution" + "entity.name.type" ], "settings": { "fontStyle": "underline", diff --git a/extensions/theme-defaults/package.json b/extensions/theme-defaults/package.json index 39c00d37b7..fbfc50afa3 100644 --- a/extensions/theme-defaults/package.json +++ b/extensions/theme-defaults/package.json @@ -5,7 +5,6 @@ "categories": [ "Themes" ], "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-defaults/themes/dark_plus.json b/extensions/theme-defaults/themes/dark_plus.json index 1898153ba8..e73cc3a09a 100644 --- a/extensions/theme-defaults/themes/dark_plus.json +++ b/extensions/theme-defaults/themes/dark_plus.json @@ -21,8 +21,6 @@ "support.class", "support.type", "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution", "entity.name.class", "storage.type.numeric.go", "storage.type.byte.go", @@ -69,10 +67,10 @@ } }, { - "name": "Control flow / Special keywords", + "name": "Control flow keywords", "scope": [ "keyword.control", - "source.cpp keyword.operator.new", + "keyword.operator.new.cpp", "keyword.operator.delete", "keyword.other.using", "keyword.other.operator" diff --git a/extensions/theme-defaults/themes/hc_black.json b/extensions/theme-defaults/themes/hc_black.json index 8119256d5f..870681495d 100644 --- a/extensions/theme-defaults/themes/hc_black.json +++ b/extensions/theme-defaults/themes/hc_black.json @@ -26,8 +26,6 @@ "support.class", "support.type", "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution", "entity.name.class", "storage.type.cs", "storage.type.generic.cs", @@ -67,11 +65,11 @@ } }, { - "name": "Control flow / Special keywords", + "name": "Control flow keywords", "scope": [ "keyword.control", - "source.cpp keyword.operator.new", - "source.cpp keyword.operator.delete", + "keyword.operator.new.cpp", + "keyword.operator.delete.cpp", "keyword.other.using", "keyword.other.operator" ], diff --git a/extensions/theme-defaults/themes/light_plus.json b/extensions/theme-defaults/themes/light_plus.json index 7138f045d5..ce23ed901d 100644 --- a/extensions/theme-defaults/themes/light_plus.json +++ b/extensions/theme-defaults/themes/light_plus.json @@ -21,8 +21,6 @@ "support.class", "support.type", "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution", "entity.name.class", "storage.type.numeric.go", "storage.type.byte.go", @@ -69,11 +67,11 @@ } }, { - "name": "Control flow / Special keywords", + "name": "Control flow keywords", "scope": [ "keyword.control", - "source.cpp keyword.operator.new", - "source.cpp keyword.operator.delete", + "keyword.operator.new.cpp", + "keyword.operator.delete.cpp", "keyword.other.using", "keyword.other.operator" ], diff --git a/extensions/theme-kimbie-dark/package.json b/extensions/theme-kimbie-dark/package.json index 1031c34d2e..06682901e0 100644 --- a/extensions/theme-kimbie-dark/package.json +++ b/extensions/theme-kimbie-dark/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json index 4b0eb5bdfc..fac06fd00d 100644 --- a/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json +++ b/extensions/theme-kimbie-dark/themes/kimbie-dark-color-theme.json @@ -147,9 +147,7 @@ "scope": [ "support.class", "entity.name.class", - "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution" + "entity.name.type" ], "settings": { "foreground": "#f06431" diff --git a/extensions/theme-monokai-dimmed/package.json b/extensions/theme-monokai-dimmed/package.json index 66c4711d9a..f64721a898 100644 --- a/extensions/theme-monokai-dimmed/package.json +++ b/extensions/theme-monokai-dimmed/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json index 5f5e5cff91..ed325071b6 100644 --- a/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json +++ b/extensions/theme-monokai-dimmed/themes/dimmed-monokai-color-theme.json @@ -143,7 +143,7 @@ }, { "name": "Class name", - "scope": "entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution", + "scope": "entity.name.class, entity.name.type", "settings": { "fontStyle": "", "foreground": "#9B0000", @@ -255,7 +255,7 @@ } }, { - "name": "Keyword Control / Special", + "name": "Keyword Control", "scope": [ "keyword.control", "keyword.operator.new.cpp", diff --git a/extensions/theme-monokai/package.json b/extensions/theme-monokai/package.json index 13b2db10d0..550f22933d 100644 --- a/extensions/theme-monokai/package.json +++ b/extensions/theme-monokai/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/theme-monokai/themes/monokai-color-theme.json b/extensions/theme-monokai/themes/monokai-color-theme.json index c16fa3c557..14d616f615 100644 --- a/extensions/theme-monokai/themes/monokai-color-theme.json +++ b/extensions/theme-monokai/themes/monokai-color-theme.json @@ -205,7 +205,7 @@ }, { "name": "Class name", - "scope": "entity.name.type, entity.name.class, entity.name.namespace, entity.name.scope-resolution", + "scope": "entity.name.type, entity.name.class", "settings": { "fontStyle": "underline", "foreground": "#A6E22E" diff --git a/extensions/theme-quietlight/package.json b/extensions/theme-quietlight/package.json index 0263925eee..0620f73088 100644 --- a/extensions/theme-quietlight/package.json +++ b/extensions/theme-quietlight/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/theme-quietlight/themes/quietlight-color-theme.json b/extensions/theme-quietlight/themes/quietlight-color-theme.json index 38681612b4..67f7caa4da 100644 --- a/extensions/theme-quietlight/themes/quietlight-color-theme.json +++ b/extensions/theme-quietlight/themes/quietlight-color-theme.json @@ -125,8 +125,6 @@ "name": "Classes", "scope": [ "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution", "entity.other.inherited-class", "support.class" ], diff --git a/extensions/theme-red/package.json b/extensions/theme-red/package.json index ba751a33e4..4b4f294fc5 100644 --- a/extensions/theme-red/package.json +++ b/extensions/theme-red/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-seti/package.json b/extensions/theme-seti/package.json index a9721611a6..554119b52b 100644 --- a/extensions/theme-seti/package.json +++ b/extensions/theme-seti/package.json @@ -5,7 +5,6 @@ "displayName": "%displayName%", "description": "%description%", "publisher": "vscode", - "license": "MIT", "icon": "icons/seti-circular-128x128.png", "scripts": { "update": "node ./build/update-icon-theme.js" diff --git a/extensions/theme-solarized-dark/package.json b/extensions/theme-solarized-dark/package.json index 427b50fe48..bb43708ca1 100644 --- a/extensions/theme-solarized-dark/package.json +++ b/extensions/theme-solarized-dark/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json index f2ee483bea..5605aba721 100644 --- a/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json +++ b/extensions/theme-solarized-dark/themes/solarized-dark-color-theme.json @@ -72,9 +72,7 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution" + "entity.name.type" ], "settings": { "fontStyle": "", diff --git a/extensions/theme-solarized-light/package.json b/extensions/theme-solarized-light/package.json index 3afb2b7ed9..1925afaa39 100644 --- a/extensions/theme-solarized-light/package.json +++ b/extensions/theme-solarized-light/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json index 8cc7e74a77..b94aeb71de 100644 --- a/extensions/theme-solarized-light/themes/solarized-light-color-theme.json +++ b/extensions/theme-solarized-light/themes/solarized-light-color-theme.json @@ -72,9 +72,7 @@ "name": "Class name", "scope": [ "entity.name.class", - "entity.name.type", - "entity.name.namespace", - "entity.name.scope-resolution" + "entity.name.type" ], "settings": { "foreground": "#268BD2" @@ -221,14 +219,16 @@ "meta.diff.header" ], "settings": { + "background": "#b58900", "fontStyle": "italic", - "foreground": "#268bd2" + "foreground": "#E0EDDD" } }, { "name": "diff: deleted", "scope": "markup.deleted", "settings": { + "background": "#eee8d5", "fontStyle": "", "foreground": "#dc322f" } @@ -237,6 +237,7 @@ "name": "diff: changed", "scope": "markup.changed", "settings": { + "background": "#eee8d5", "fontStyle": "", "foreground": "#cb4b16" } @@ -245,6 +246,7 @@ "name": "diff: inserted", "scope": "markup.inserted", "settings": { + "background": "#eee8d5", "foreground": "#219186" } }, @@ -415,7 +417,7 @@ "tab.activeBackground": "#FDF6E3", "tab.inactiveForeground": "#586E75", "tab.inactiveBackground": "#D3CBB7", - "tab.activeModifiedBorder": "#cb4b16", + "tab.modifiedBorder": "#cb4b16", // "tab.activeBackground": "", // "tab.activeForeground": "", // "tab.inactiveForeground": "", diff --git a/extensions/theme-tomorrow-night-blue/package.json b/extensions/theme-tomorrow-night-blue/package.json index 1266ac58ca..bed66ce548 100644 --- a/extensions/theme-tomorrow-night-blue/package.json +++ b/extensions/theme-tomorrow-night-blue/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "themes": [ diff --git a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json index 6c985d1ea5..2ca39bf565 100644 --- a/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json +++ b/extensions/theme-tomorrow-night-blue/themes/tomorrow-night-blue-theme.json @@ -101,7 +101,7 @@ }, { "name": "Class, Support", - "scope": "entity.name.class, entity.name.type, entity.name.namespace, entity.name.scope-resolution, support.type, support.class", + "scope": "entity.name.class, entity.name.type, support.type, support.class", "settings": { "fontStyle": "", "foreground": "#FFEEAD" diff --git a/extensions/vscode-colorize-tests/package.json b/extensions/vscode-colorize-tests/package.json index 702e36e66c..517429bb6d 100644 --- a/extensions/vscode-colorize-tests/package.json +++ b/extensions/vscode-colorize-tests/package.json @@ -3,7 +3,6 @@ "description": "Colorize tests for VS Code", "version": "0.0.1", "publisher": "vscode", - "license": "MIT", "private": true, "engines": { "vscode": "*" @@ -12,7 +11,7 @@ "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../build/gulpfile.extensions.js compile-extension:vscode-colorize-tests ./tsconfig.json" }, "devDependencies": { - "@types/node": "^10.14.8", + "@types/node": "^10.12.21", "mocha-junit-reporter": "^1.17.0", "mocha-multi-reporters": "^1.1.7", "vscode": "1.1.5" diff --git a/extensions/vscode-colorize-tests/yarn.lock b/extensions/vscode-colorize-tests/yarn.lock index 368b81f2f9..46684d06b5 100644 --- a/extensions/vscode-colorize-tests/yarn.lock +++ b/extensions/vscode-colorize-tests/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.21" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.21.tgz#7e8a0c34cf29f4e17a36e9bd0ea72d45ba03908e" + integrity sha512-CBgLNk4o3XMnqMc0rhb6lc77IwShMEglz05deDcn2lQxyXEZivfwgYJu7SMha9V5XcrP6qZuevTHV/QrN2vjKQ== ajv@^5.1.0: version "5.3.0" diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json index cf87ab6c73..6377065d87 100644 --- a/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -21,7 +21,7 @@ ], "main": "./out/extension", "devDependencies": { - "@types/node": "^10.14.8", + "@types/node": "^10.12.21", "vscode": "1.1.5" }, "contributes": { diff --git a/extensions/vscode-test-resolver/src/extension.ts b/extensions/vscode-test-resolver/src/extension.ts index 3823f6e33d..6d2d786823 100644 --- a/extensions/vscode-test-resolver/src/extension.ts +++ b/extensions/vscode-test-resolver/src/extension.ts @@ -26,11 +26,10 @@ export function activate(context: vscode.ExtensionContext) { progress.report({ message: 'Starting Test Resolver' }); outputChannel = vscode.window.createOutputChannel('TestResolver'); - let isResolved = false; + let isStarted = false; async function processError(message: string) { outputChannel.appendLine(message); - if (!isResolved) { - isResolved = true; + if (!isStarted) { outputChannel.show(); const result = await vscode.window.showErrorMessage(message, { modal: true }, ...getActions()); @@ -49,7 +48,7 @@ export function activate(context: vscode.ExtensionContext) { if (chr === CharCode.LineFeed) { const match = lastProgressLine.match(/Extension host agent listening on (\d+)/); if (match) { - isResolved = true; + isStarted = true; res(new vscode.ResolvedAuthority('localhost', parseInt(match[1], 10))); // success! } lastProgressLine = ''; @@ -66,30 +65,47 @@ export function activate(context: vscode.ExtensionContext) { return; } - const { updateUrl, commit, quality, serverDataFolderName, dataFolderName } = getProductConfiguration(); - const serverCommand = process.platform === 'win32' ? 'server.bat' : 'server.sh'; - const commandArgs = ['--port=0', '--disable-telemetry']; - const env = getNewEnv(); - const remoteDataDir = process.env['TESTRESOLVER_DATA_FOLDER'] || path.join(os.homedir(), serverDataFolderName || `${dataFolderName}-testresolver`); - env['VSCODE_AGENT_FOLDER'] = remoteDataDir; - outputChannel.appendLine(`Using data folder at ${remoteDataDir}`); - + const { updateUrl, commit, quality } = getProductConfiguration(); if (!commit) { // dev mode const vscodePath = path.resolve(path.join(context.extensionPath, '..', '..')); - const serverCommandPath = path.join(vscodePath, 'resources', 'server', 'bin-dev', serverCommand); - extHostProcess = cp.spawn(serverCommandPath, commandArgs, { env, cwd: vscodePath }); + const nodeExec = process.platform === 'win32' ? 'node.exe' : 'node'; + const nodePath = path.join(vscodePath, '.build', 'node-remote', nodeExec); + + if (!fs.existsSync(nodePath)) { + try { + progress.report({ message: 'Installing node' }); + outputChannel.appendLine(`Installing node at ${nodePath}`); + cp.execSync(`node ${path.join(vscodePath, 'node_modules/gulp/bin/gulp.js')} node-remote`); + } catch (e) { + processError(`Problem downloading node: ${e.message}`); + + } + } + outputChannel.appendLine(`Using node at ${nodePath}`); + + const env = getNewEnv(); + env['PATH'] = path.join(vscodePath, 'resources', 'server', 'bin') + path.delimiter + env['PATH']; // allow calling code-dev.sh + + outputChannel.appendLine(env['PATH'] || ''); + + extHostProcess = cp.spawn(nodePath, [path.join('out', 'remoteExtensionHostAgent'), '--port=0'], { cwd: vscodePath, env }); } else { - const serverBin = path.join(remoteDataDir, 'bin'); + const serverBin = path.resolve(os.homedir(), '.vscode-remote', 'bin'); progress.report({ message: 'Installing VSCode Server' }); const serverLocation = await downloadAndUnzipVSCodeServer(updateUrl, commit, quality, serverBin); outputChannel.appendLine(`Using server build at ${serverLocation}`); - extHostProcess = cp.spawn(path.join(serverLocation, serverCommand), commandArgs, { env, cwd: serverLocation }); + const commandArgs = ['--port=0', '--disable-telemetry']; + + const env = getNewEnv(); + env['PATH'] = path.join(serverLocation, 'bin') + path.delimiter + env['PATH']; // code command for the terminal + + extHostProcess = cp.spawn(path.join(serverLocation, 'server.sh'), commandArgs, { env, cwd: serverLocation }); } extHostProcess.stdout.on('data', (data: Buffer) => processOutput(data.toString())); extHostProcess.stderr.on('data', (data: Buffer) => processOutput(data.toString())); - extHostProcess.on('error', (error: Error) => processError(`server failed with error:\n${error.message}`)); - extHostProcess.on('close', (code: number) => processError(`server closed unexpectedly.\nError code: ${code}`)); + extHostProcess.on('error', (error: Error) => processError(`remoteExtensionHostAgent failed with error:\n${error.message}`)); + extHostProcess.on('close', (code: number) => processError(`remoteExtensionHostAgent closed unexpectedly.\nError code: ${code}`)); }); } @@ -117,6 +133,7 @@ export function activate(context: vscode.ExtensionContext) { outputChannel.show(); } }); + } type ActionItem = (vscode.MessageItem & { execute: () => void; }); @@ -153,8 +170,6 @@ export interface IProductConfiguration { updateUrl: string; commit: string; quality: string; - dataFolderName: string; - serverDataFolderName?: string; } function getProductConfiguration(): IProductConfiguration { diff --git a/extensions/vscode-test-resolver/yarn.lock b/extensions/vscode-test-resolver/yarn.lock index 925cef2c14..4cb3781773 100644 --- a/extensions/vscode-test-resolver/yarn.lock +++ b/extensions/vscode-test-resolver/yarn.lock @@ -2,10 +2,10 @@ # yarn lockfile v1 -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^10.12.21": + version "10.12.30" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.30.tgz#4c2b4f0015f214f8158a347350481322b3b29b2f" + integrity sha512-nsqTN6zUcm9xtdJiM9OvOJ5EF0kOI8f1Zuug27O/rgtxCRJHGqncSWfCMZUP852dCKPsDsYXGvBhxfRjDBkF5Q== ajv@^6.5.5: version "6.10.0" diff --git a/extensions/xml/package.json b/extensions/xml/package.json index 2e6cc49fd6..985266edf9 100644 --- a/extensions/xml/package.json +++ b/extensions/xml/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, "contributes": { "languages": [{ diff --git a/extensions/yaml/package.json b/extensions/yaml/package.json index 5b12e0fbc5..79e2eecc31 100644 --- a/extensions/yaml/package.json +++ b/extensions/yaml/package.json @@ -4,7 +4,6 @@ "description": "%description%", "version": "1.0.0", "publisher": "vscode", - "license": "MIT", "engines": { "vscode": "*" }, diff --git a/extensions/yarn.lock b/extensions/yarn.lock index fd211376d4..659f98aa61 100644 --- a/extensions/yarn.lock +++ b/extensions/yarn.lock @@ -2,7 +2,7 @@ # yarn lockfile v1 -typescript@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202" - integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw== +typescript@3.5.0-dev.20190522: + version "3.5.0-dev.20190522" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.0-dev.20190522.tgz#ade4702c6e599a7e8905d7acaaf416f7e32ba0fc" + integrity sha512-V+QsNMtXl8lGwov4O04D+E6vtiL0TWEpz6iDxI2tAZizEn7y8Hh9SXzz3JRWepr7dfdqqxEv9CT3J18zpaZKJQ== diff --git a/package.json b/package.json index 8062ace563..0e50fff810 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "author": { "name": "Microsoft Corporation" }, - "license": "MIT", "main": "./out/main", "private": true, "scripts": { @@ -27,8 +26,7 @@ "strict-null-check": "tsc -p src/tsconfig.strictNullChecks.json", "strict-null-check-watch": "tsc -p src/tsconfig.strictNullChecks.json --watch", "strict-initialization-watch": "tsc --watch -p src/tsconfig.json --noEmit --strictPropertyInitialization", - "web": "node resources/server/bin-dev/code-web.js", - "install-server": "git fetch distro && git checkout distro/distro -- src/vs/server resources/server && git reset HEAD src/vs/server resources/server" + "web": "node scripts/code-web.js" }, "dependencies": { "@angular/animations": "~4.1.3", @@ -61,27 +59,25 @@ "native-keymap": "1.2.5", "native-watchdog": "1.0.0", "ng2-charts": "^1.6.0", - "node-pty": "0.9.0-beta17", - "onigasm-umd": "^2.2.2", + "node-pty": "0.9.0-beta9", "pretty-data": "^0.40.0", "reflect-metadata": "^0.1.8", "rxjs": "5.4.0", "sanitize-html": "^1.19.1", "semver": "^5.5.0", "slickgrid": "github:anthonydresser/SlickGrid#2.3.29", - "spdlog": "^0.9.0", + "spdlog": "0.8.1", "sudo-prompt": "8.2.0", "v8-inspect-profiler": "^0.0.20", "vscode-chokidar": "1.6.5", - "vscode-nsfw": "1.1.2", + "vscode-debugprotocol": "1.34.0", + "vscode-nsfw": "1.1.1", "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.2.5", "vscode-sqlite3": "4.0.7", - "vscode-textmate": "^4.1.1", - "xterm": "3.15.0-beta23", - "xterm-addon-search": "0.1.0-beta5", - "xterm-addon-web-links": "0.1.0-beta9", - "yauzl": "^2.9.2", + "vscode-textmate": "^4.0.1", + "vscode-xterm": "3.14.0-beta3", + "yauzl": "^2.9.1", "yazl": "^2.4.3", "zone.js": "^0.8.4" }, @@ -102,6 +98,7 @@ "ansi-colors": "^3.2.3", "asar": "^0.14.0", "chromium-pickle-js": "^0.2.0", + "clean-css": "3.4.6", "copy-webpack-plugin": "^4.5.2", "coveralls": "^3.0.3", "cson-parser": "^1.3.3", @@ -164,14 +161,13 @@ "tslint": "^5.16.0", "tslint-microsoft-contrib": "^6.0.0", "typemoq": "^0.3.2", - "typescript": "3.5.1", + "typescript": "3.4.5", "typescript-formatter": "7.1.0", "uglify-es": "^3.0.18", "underscore": "^1.8.2", "vinyl": "^2.0.0", "vinyl-fs": "^3.0.0", "vsce": "1.48.0", - "vscode-debugprotocol": "1.35.0", "vscode-nls-dev": "3.2.5", "webpack": "^4.16.5", "webpack-cli": "^3.1.0", diff --git a/remote/installDevModules.sh b/remote/installDevModules.sh new file mode 100755 index 0000000000..3b8941d002 --- /dev/null +++ b/remote/installDevModules.sh @@ -0,0 +1,20 @@ +#!/bin/bash +set -ex + +# Install Node and Yarn +export NODE_VERSION=10.2.1 +export YARN_VERSION=1.10.1 +curl -fsSLO --compressed "https://nodejs.org/dist/v$NODE_VERSION/node-v$NODE_VERSION-linux-x64.tar.xz" +curl -fsSLO --compressed "https://yarnpkg.com/downloads/$YARN_VERSION/yarn-v$YARN_VERSION.tar.gz" +tar -xJf "node-v$NODE_VERSION-linux-x64.tar.xz" -C "$HOME" --no-same-owner +tar -xzf "yarn-v$YARN_VERSION.tar.gz" -C "$HOME" +mkdir -p "$HOME/bin" +ln -s "$HOME/node-v$NODE_VERSION-linux-x64/bin/node" "$HOME/bin/node" +ln -s "$HOME/yarn-v$YARN_VERSION/bin/yarn" "$HOME/bin/yarn" +ln -s "$HOME/yarn-v$YARN_VERSION/bin/yarnpkg" "$HOME/bin/yarnpkg" +rm "node-v$NODE_VERSION-linux-x64.tar.xz" "yarn-v$YARN_VERSION.tar.gz" + +# Compile native /remote node_modules +PATH="$HOME/bin:$PATH" \ +PYTHON=/usr/bin/python2.7 \ +yarn --ignore-optional diff --git a/remote/installDevPackagesAsRoot.sh b/remote/installDevPackagesAsRoot.sh new file mode 100755 index 0000000000..1df37767c9 --- /dev/null +++ b/remote/installDevPackagesAsRoot.sh @@ -0,0 +1,16 @@ +#!/bin/bash +set -ex + +# Install libraries and tools +apt-get update +apt-get install -y \ + curl \ + make \ + gcc \ + g++ \ + python2.7 \ + libx11-dev \ + libxkbfile-dev \ + libsecret-1-dev \ + xz-utils +rm -rf /var/lib/apt/lists/* diff --git a/remote/launchDevMode.sh b/remote/launchDevMode.sh new file mode 100755 index 0000000000..cd7ab12976 --- /dev/null +++ b/remote/launchDevMode.sh @@ -0,0 +1,17 @@ +#!/bin/bash +set -e + +export NODE_ENV=development +export VSCODE_DEV=1 +export VSCODE_INJECT_NODE_MODULE_LOOKUP_PATH="$HOME/.vscode-remote/bin/dev-remote/node_modules" + +cd $VSCODE_REPO + +if [ -z "$extensions" ] ; then + echo No extensions to install. + mkdir -p /root/.vscode-remote +else + (PATH="$HOME/bin:$PATH" node out/remoteExtensionHostAgent.js ${VSCODE_TELEMETRY_ARG} ${extensions} || true) +fi + +PATH="$HOME/bin:$PATH" node out/remoteExtensionHostAgent.js ${VSCODE_TELEMETRY_ARG} --port $PORT diff --git a/remote/package.json b/remote/package.json index 34e2855e3c..cd8b8c6673 100644 --- a/remote/package.json +++ b/remote/package.json @@ -13,15 +13,13 @@ "minimist": "1.2.0", "native-watchdog": "1.0.0", "node-pty": "0.8.1", - "onigasm-umd": "^2.2.2", "semver": "^5.5.0", - "spdlog": "^0.9.0", + "spdlog": "0.8.1", "vscode-chokidar": "1.6.5", "vscode-nsfw": "1.1.1", "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.2.5", - "vscode-textmate": "^4.1.1", - "yauzl": "^2.9.2", + "yauzl": "^2.9.1", "yazl": "^2.4.3" }, "optionalDependencies": { diff --git a/remote/yarn.lock b/remote/yarn.lock index 0b32cb56db..2df672960f 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -80,12 +80,10 @@ binary-extensions@^1.0.0: resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.10.0.tgz#9aeb9a6c5e88638aad171e167f5900abe24835d0" integrity sha1-muuabF6IY4qtFx4Wf1kAq+JINdA= -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" +bindings@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" + integrity sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw== bl@^1.0.0: version "1.2.2" @@ -283,18 +281,13 @@ extract-opts@^3.2.0: editions "^1.1.1" typechecker "^4.3.0" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= +fd-slicer@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.0.1.tgz#8b5bcbd9ec327c5041bf9ab023fd6750f1177e65" + integrity sha1-i1vL2ewyfFBBv5qwI/1nUPEXfmU= dependencies: pend "~1.2.0" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" @@ -604,7 +597,7 @@ nan@2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== -nan@2.8.0: +nan@2.8.0, nan@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo= @@ -614,11 +607,6 @@ nan@^2.10.0: resolved "https://registry.yarnpkg.com/nan/-/nan-2.11.0.tgz#574e360e4d954ab16966ec102c0c049fd961a099" integrity sha512-F4miItu2rGnV2ySkXOQoA8FKz/SR2Q2sWP0sbTxNxz/tuokeC8WxOhPMcwi0qIyGtVn/rrSeLbvVkznqCdwYnw== -nan@^2.12.1, nan@^2.14.0: - version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - native-watchdog@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/native-watchdog/-/native-watchdog-1.0.0.tgz#97344e83cd6815a8c8e6c44a52e7be05832e65ca" @@ -695,18 +683,6 @@ once@^1.3.1, once@^1.4.0: dependencies: wrappy "1" -onigasm-umd@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" - integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== - -oniguruma@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.1.0.tgz#106ddf7eb42507d0442ac68b187c4f7fdf052c83" - integrity sha512-mV+6HcDNQ38vM8HVKM+MJyXO4EtSigwIZhq023A4rA8Am4dMlGhUkPwudDykExYR45oLrssR/Ep7PZCQ1OM3pA== - dependencies: - nan "^2.12.1" - os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" @@ -936,14 +912,14 @@ socks@~2.2.0: ip "^1.1.5" smart-buffer "^4.0.1" -spdlog@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.9.0.tgz#c85dd9d0b9cd385f6f3f5b92dc9d2e1691092b5c" - integrity sha512-AeLWPCYjGi4w5DfpXFKb9pCdgMe4gFBMroGfgwXiNfzwmcNYGoFQkIuD1MChZBR1Iwrx0nGhsTSHFslt/qfTAQ== +spdlog@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.8.1.tgz#dfb3f3422ab3efe32be79e4769b95440ed72699f" + integrity sha512-W0s8IOXpn86md+8PJ4mJeB/22thykzH5YaNc3Rgnql4x4/zFIhvNiEx6/a1arnqvmJF0HtRO0Ehlswg0WcwTLQ== dependencies: - bindings "^1.5.0" + bindings "^1.3.0" mkdirp "^0.5.1" - nan "^2.14.0" + nan "^2.8.0" string-width@^1.0.1: version "1.0.2" @@ -1103,13 +1079,6 @@ vscode-ripgrep@^1.2.5: resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.2.5.tgz#2093c8f36d52bd2dab9eb45b003dd02533c5499c" integrity sha512-n5XBm9od5hahpljw9T8wbkuMnAY7LlAG1OyEEtcCZEX9aCHFuBKSP0IcvciGRTbtWRovNuT83A2iRjt6PL3bLg== -vscode-textmate@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.1.1.tgz#857e836fbc13a376ec624242437e1747d79610a9" - integrity sha512-xBjq9LH6fMhWDhIVkbKlB1JeCu6lT3FI/QKN24Xi4RKPBUm16IhHTqs6Q6SUGewkNsFZGkb1tJdZsuMnlmVpgw== - dependencies: - oniguruma "^7.0.0" - vscode-windows-ca-certs@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/vscode-windows-ca-certs/-/vscode-windows-ca-certs-0.1.0.tgz#d58eeb40b536130918cfde2b01e6dc7e5c1bd757" @@ -1139,13 +1108,13 @@ xtend@^4.0.0: resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" integrity sha1-pcbVMr5lbiPbgg77lDofBJmNY68= -yauzl@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= +yauzl@^2.9.1: + version "2.9.1" + resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" + integrity sha1-qBmB6nCleUYTOIPwKcWCGok1mn8= dependencies: buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" + fd-slicer "~1.0.1" yazl@^2.4.3: version "2.4.3" diff --git a/resources/linux/rpm/dependencies.json b/resources/linux/rpm/dependencies.json index 34f127e1ae..d0b64c4fa6 100644 --- a/resources/linux/rpm/dependencies.json +++ b/resources/linux/rpm/dependencies.json @@ -63,5 +63,83 @@ "libxcb.so.1()(64bit)", "libxkbfile.so.1()(64bit)", "libsecret-1.so.0()(64bit)" + ], + "i386": [ + "ld-linux.so.2", + "ld-linux.so.2(GLIBC_2.1)", + "libX11-xcb.so.1", + "libX11.so.6", + "libXcomposite.so.1", + "libXcursor.so.1", + "libXdamage.so.1", + "libXext.so.6", + "libXfixes.so.3", + "libXi.so.6", + "libXrandr.so.2", + "libXrender.so.1", + "libXss.so.1", + "libXtst.so.6", + "libasound.so.2", + "libatk-1.0.so.0", + "libc.so.6", + "libc.so.6(GLIBC_2.0)", + "libc.so.6(GLIBC_2.1)", + "libc.so.6(GLIBC_2.1.3)", + "libc.so.6(GLIBC_2.11)", + "libc.so.6(GLIBC_2.2)", + "libc.so.6(GLIBC_2.2.3)", + "libc.so.6(GLIBC_2.3)", + "libc.so.6(GLIBC_2.3.2)", + "libc.so.6(GLIBC_2.3.4)", + "libc.so.6(GLIBC_2.4)", + "libc.so.6(GLIBC_2.6)", + "libc.so.6(GLIBC_2.7)", + "libcairo.so.2", + "libcups.so.2", + "libdbus-1.so.3", + "libdl.so.2", + "libdl.so.2(GLIBC_2.0)", + "libdl.so.2(GLIBC_2.1)", + "libexpat.so.1", + "libfontconfig.so.1", + "libfreetype.so.6", + "libgcc_s.so.1", + "libgcc_s.so.1(GCC_4.0.0)", + "libgcc_s.so.1(GLIBC_2.0)", + "libgdk-x11-2.0.so.0", + "libgdk_pixbuf-2.0.so.0", + "libgio-2.0.so.0", + "libglib-2.0.so.0", + "libgmodule-2.0.so.0", + "libgobject-2.0.so.0", + "libgtk-3.so.0", + "libm.so.6", + "libm.so.6(GLIBC_2.0)", + "libm.so.6(GLIBC_2.1)", + "libnspr4.so", + "libnss3.so", + "libnssutil3.so", + "libpango-1.0.so.0", + "libpangocairo-1.0.so.0", + "libpthread.so.0", + "libpthread.so.0(GLIBC_2.0)", + "libpthread.so.0(GLIBC_2.1)", + "libpthread.so.0(GLIBC_2.2)", + "libpthread.so.0(GLIBC_2.2.3)", + "libpthread.so.0(GLIBC_2.3.2)", + "libpthread.so.0(GLIBC_2.3.3)", + "librt.so.1", + "librt.so.1(GLIBC_2.2)", + "libsmime3.so", + "libstdc++.so.6", + "libstdc++.so.6(GLIBCXX_3.4)", + "libstdc++.so.6(GLIBCXX_3.4.10)", + "libstdc++.so.6(GLIBCXX_3.4.11)", + "libstdc++.so.6(GLIBCXX_3.4.14)", + "libstdc++.so.6(GLIBCXX_3.4.15)", + "libstdc++.so.6(GLIBCXX_3.4.9)", + "libxcb.so.1", + "libxkbfile.so.1", + "libsecret-1.so.0" ] } \ No newline at end of file diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index da01223b00..0ff31d69dd 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -6,7 +6,6 @@ COMMIT="@@COMMIT@@" APP_NAME="@@APPNAME@@" QUALITY="@@QUALITY@@" NAME="@@NAME@@" -DATAFOLDER="@@DATAFOLDER@@" VSCODE_PATH="$(dirname "$(dirname "$(realpath "$0")")")" ELECTRON="$VSCODE_PATH/$NAME.exe" if grep -qi Microsoft /proc/version; then @@ -27,7 +26,7 @@ if grep -qi Microsoft /proc/version; then # replace \r\n with \n in WSL_EXT_WLOC WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh WIN_CODE_CMD=$(wslpath -w "$VSCODE_PATH/bin/$APP_NAME.cmd") - "$WSL_CODE" "$COMMIT" "$QUALITY" "$WIN_CODE_CMD" "$APP_NAME" "$DATAFOLDER" "$@" + "$WSL_CODE" $COMMIT $QUALITY "$WIN_CODE_CMD" "$APP_NAME" "$@" exit $? else CLI=$(wslpath -m "$VSCODE_PATH/resources/app/out/cli.js") diff --git a/scripts/code-web.js b/scripts/code-web.js new file mode 100644 index 0000000000..7721681745 --- /dev/null +++ b/scripts/code-web.js @@ -0,0 +1,24 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +const opn = require('opn'); +const cp = require('child_process'); +const path = require('path'); + +const proc = cp.execFile(path.join(__dirname, process.platform === 'win32' ? 'remoteExtensionAgent.bat' : 'remoteExtensionAgent.sh')); + +let launched = false; +proc.stdout.on("data", data => { + if (!launched && data.toString().indexOf('Extension host agent listening on 8000')) { + launched = true; + + setTimeout(() => { + const url = 'http://127.0.0.1:8000'; + console.log(`Open ${url} in your browser`); + + opn(url); + }, 100); + } +}); \ No newline at end of file diff --git a/scripts/code.sh b/scripts/code.sh index b0b112bc23..1f7cda590a 100755 --- a/scripts/code.sh +++ b/scripts/code.sh @@ -58,7 +58,7 @@ function code() { function code-wsl() { # in a wsl shell - local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat" 2>/dev/null) + local WIN_CODE_CLI_CMD=$(wslpath -w "$ROOT/scripts/code-cli.bat") if ! [ -z "$WIN_CODE_CLI_CMD" ]; then local WSL_EXT_ID="ms-vscode-remote.remote-wsl" local WSL_EXT_WLOC=$(cmd.exe /c "$WIN_CODE_CLI_CMD" --locate-extension $WSL_EXT_ID) diff --git a/scripts/test-integration.bat b/scripts/test-integration.bat index 1e25bf29df..ff579e873d 100644 --- a/scripts/test-integration.bat +++ b/scripts/test-integration.bat @@ -32,10 +32,6 @@ call .\scripts\test.bat --runGlob **\*.integrationTest.js %* call .\scripts\node-electron.bat .\node_modules\mocha\bin\_mocha .\extensions\*\server\out\test\**\*.test.js if %errorlevel% neq 0 exit /b %errorlevel% -if exist ".\resources\server\test\test-remote-integration.bat" ( - call .\resources\server\test\test-remote-integration.bat -) - rmdir /s /q %VSCODEUSERDATADIR% popd diff --git a/scripts/test-integration.sh b/scripts/test-integration.sh index 3eb21c4bf9..cab90665c4 100755 --- a/scripts/test-integration.sh +++ b/scripts/test-integration.sh @@ -27,10 +27,6 @@ mkdir -p $ROOT/extensions/emmet/test-fixtures ./scripts/code.sh $ROOT/extensions/emmet/test-fixtures --extensionDevelopmentPath=$ROOT/extensions/emmet --extensionTestsPath=$ROOT/extensions/emmet/out/test --disable-extensions --user-data-dir=$VSCODEUSERDATADIR --skip-getting-started rm -rf $ROOT/extensions/emmet/test-fixtures -if [ -f ./resources/server/test/test-remote-integration.sh ]; then - ./resources/server/test/test-remote-integration.sh -fi - # Tests in commonJS cd $ROOT/extensions/css-language-features/server && $ROOT/scripts/node-electron.sh test/index.js cd $ROOT/extensions/html-language-features/server && $ROOT/scripts/node-electron.sh test/index.js diff --git a/src/main.js b/src/main.js index 62fec18aa4..52ece7e3ff 100644 --- a/src/main.js +++ b/src/main.js @@ -205,7 +205,7 @@ function parseCLIArgs() { function setCurrentWorkingDirectory() { try { if (process.platform === 'win32') { - process.env['VSCODE_CWD'] = process.cwd(); // remember as environment variable + process.env['VSCODE_CWD'] = process.cwd(); // remember as environment letiable process.chdir(path.dirname(app.getPath('exe'))); // always set application folder as cwd } else if (process.env['VSCODE_CWD']) { process.chdir(process.env['VSCODE_CWD']); @@ -347,4 +347,4 @@ function getUserDefinedLocale() { return undefined; }); } -//#endregion +//#endregion \ No newline at end of file diff --git a/src/sql/azdata.proposed.d.ts b/src/sql/azdata.proposed.d.ts index dce2084038..25a9b52583 100644 --- a/src/sql/azdata.proposed.d.ts +++ b/src/sql/azdata.proposed.d.ts @@ -4488,8 +4488,8 @@ declare module 'azdata' { * } * ``` * @export - * @param notebook provider - * @returns disposable + * @param {NotebookProvider} provider + * @returns {vscode.Disposable} */ export function registerNotebookProvider(provider: NotebookProvider): vscode.Disposable; diff --git a/src/sql/base/browser/ui/button/button.ts b/src/sql/base/browser/ui/button/button.ts index a2e32c0bfa..16d89c6569 100644 --- a/src/sql/base/browser/ui/button/button.ts +++ b/src/sql/base/browser/ui/button/button.ts @@ -18,7 +18,7 @@ export class Button extends vsButton { super(container, options); this._register(DOM.addDisposableListener(this.element, DOM.EventType.FOCUS, () => { - this.element.style.outlineColor = this.buttonFocusOutline ? this.buttonFocusOutline.toString() : ''; + this.element.style.outlineColor = this.buttonFocusOutline ? this.buttonFocusOutline.toString() : null; this.element.style.outlineWidth = '1px'; })); diff --git a/src/sql/base/browser/ui/dropdownList/dropdownList.ts b/src/sql/base/browser/ui/dropdownList/dropdownList.ts index 534e3b5842..520053afa1 100644 --- a/src/sql/base/browser/ui/dropdownList/dropdownList.ts +++ b/src/sql/base/browser/ui/dropdownList/dropdownList.ts @@ -41,11 +41,11 @@ export class DropdownList extends Dropdown { if (action) { this.button = new Button(_contentContainer); this.button.label = action.label; - this._register(DOM.addDisposableListener(this.button.element, DOM.EventType.CLICK, () => { + this.toDispose.push(DOM.addDisposableListener(this.button.element, DOM.EventType.CLICK, () => { action.run(); this.hide(); })); - this._register(DOM.addDisposableListener(this.button.element, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.toDispose.push(DOM.addDisposableListener(this.button.element, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.Enter)) { e.stopPropagation(); @@ -75,7 +75,7 @@ export class DropdownList extends Dropdown { } })); - this._register(this._list.onSelectionChange(() => { + this.toDispose.push(this._list.onSelectionChange(() => { // focus on the dropdown label then hide the dropdown list this.element.focus(); this.hide(); diff --git a/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts b/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts index 3c4d1af1bf..66b506609e 100644 --- a/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts +++ b/src/sql/base/browser/ui/scrollableSplitview/scrollableSplitview.ts @@ -241,7 +241,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { } this.onRemoveItems(new ArrayIterator([item.view.id!])); }); - const disposable = combinedDisposable(onChangeDisposable, containerDisposable); + const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); const onAdd = view.onAdd ? () => view.onAdd!() : () => { }; const onRemove = view.onRemove ? () => view.onRemove!() : () => { }; @@ -292,7 +292,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { const onEndDisposable = onEnd(this.onSashEnd, this); const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); - const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); + const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]); const sashItem: ISashItem = { sash, disposable }; this.sashItems.splice(currentIndex - 1, 0, sashItem); @@ -344,7 +344,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { } this.onRemoveItems(new ArrayIterator([item.view.id!])); }); - const disposable = combinedDisposable(onChangeDisposable, containerDisposable); + const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); const onAdd = view.onAdd ? () => view.onAdd!() : () => { }; const onRemove = view.onRemove ? () => view.onRemove!() : () => { }; @@ -395,7 +395,7 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { const onEndDisposable = onEnd(this.onSashEnd, this); const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); - const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); + const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]); const sashItem: ISashItem = { sash, disposable }; this.sashItems.splice(index - 1, 0, sashItem); @@ -527,10 +527,10 @@ export class ScrollableSplitView extends HeightMap implements IDisposable { const index = firstIndex(this.sashItems, item => item.sash === sash); // This way, we can press Alt while we resize a sash, macOS style! - const disposable = combinedDisposable( + const disposable = combinedDisposable([ domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState.current, e.altKey)), domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState.current, false)) - ); + ]); const resetSashDragState = (start: number, alt: boolean) => { const sizes = this.viewItems.map(i => i.size); diff --git a/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts b/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts index 36af00cdc0..ae6035f83d 100644 --- a/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts +++ b/src/sql/base/browser/ui/table/plugins/autoSizeColumns.plugin.ts @@ -14,7 +14,7 @@ const defaultOptions: IAutoColumnSizeOptions = { autoSizeOnRender: false }; -export class AutoColumnSize implements Slick.Plugin { +export class AutoColumnSize implements Slick.Plugin { private _grid: Slick.Grid; private _$container: JQuery; private _context: CanvasRenderingContext2D; diff --git a/src/sql/base/browser/ui/taskbar/actionbar.ts b/src/sql/base/browser/ui/taskbar/actionbar.ts index 86ae2de834..0b48545e73 100644 --- a/src/sql/base/browser/ui/taskbar/actionbar.ts +++ b/src/sql/base/browser/ui/taskbar/actionbar.ts @@ -43,12 +43,13 @@ export class ActionBar extends ActionRunner implements IActionRunner { super(); this._options = options; this._context = options.context; + this._toDispose = []; if (this._options.actionRunner) { this._actionRunner = this._options.actionRunner; } else { this._actionRunner = new ActionRunner(); - this._register(this._actionRunner); + this._toDispose.push(this._actionRunner); } //this._toDispose.push(this.addEmitter(this._actionRunner)); @@ -364,6 +365,8 @@ export class ActionBar extends ActionRunner implements IActionRunner { lifecycle.dispose(this._items); this._items = []; + this._toDispose = lifecycle.dispose(this._toDispose); + this._domNode.remove(); super.dispose(); diff --git a/src/sql/platform/accounts/browser/accountDialog.ts b/src/sql/platform/accounts/browser/accountDialog.ts index 6a41d7f37e..251738a0a7 100644 --- a/src/sql/platform/accounts/browser/accountDialog.ts +++ b/src/sql/platform/accounts/browser/accountDialog.ts @@ -53,7 +53,7 @@ class AccountPanel extends ViewletPanel { protected renderBody(container: HTMLElement): void { this.accountList = new List(container, new AccountListDelegate(AccountDialog.ACCOUNTLIST_HEIGHT), [this.instantiationService.createInstance(AccountListRenderer)]); - this._register(attachListStyler(this.accountList, this.themeService)); + this.disposables.push(attachListStyler(this.accountList, this.themeService)); } protected layoutBody(size: number): void { diff --git a/src/sql/platform/connection/common/connectionManagementService.ts b/src/sql/platform/connection/common/connectionManagementService.ts index 861a8e8d5a..bcd7a50f48 100644 --- a/src/sql/platform/connection/common/connectionManagementService.ts +++ b/src/sql/platform/connection/common/connectionManagementService.ts @@ -43,6 +43,7 @@ import * as platform from 'vs/platform/registry/common/platform'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ConnectionProfileGroup, IConnectionProfileGroup } from 'sql/platform/connection/common/connectionProfileGroup'; import { Event, Emitter } from 'vs/base/common/event'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConnectionDialogService } from 'sql/workbench/services/connection/common/connectionDialogService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -50,7 +51,6 @@ import { ILogService } from 'vs/platform/log/common/log'; import * as interfaces from './interfaces'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Memento } from 'vs/workbench/common/memento'; -import { INotificationService } from 'vs/platform/notification/common/notification'; export class ConnectionManagementService extends Disposable implements IConnectionManagementService { @@ -70,7 +70,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti private _onConnectRequestSent = new Emitter(); private _onConnectionChanged = new Emitter(); private _onLanguageFlavorChanged = new Emitter(); - private _connectionGlobalStatus = new ConnectionGlobalStatus(this._notificationService); + private _connectionGlobalStatus = new ConnectionGlobalStatus(this._statusBarService); private _mementoContext: Memento; private _mementoObj: any; @@ -86,7 +86,7 @@ export class ConnectionManagementService extends Disposable implements IConnecti @IConfigurationService private _configurationService: IConfigurationService, @ICapabilitiesService private _capabilitiesService: ICapabilitiesService, @IQuickInputService private _quickInputService: IQuickInputService, - @INotificationService private _notificationService: INotificationService, + @IStatusbarService private _statusBarService: IStatusbarService, @IResourceProviderService private _resourceProviderService: IResourceProviderService, @IAngularEventingService private _angularEventing: IAngularEventingService, @IAccountManagementService private _accountManagementService: IAccountManagementService, diff --git a/src/sql/platform/query/common/queryModelService.ts b/src/sql/platform/query/common/queryModelService.ts index 605024c4bb..c6d81a506d 100644 --- a/src/sql/platform/query/common/queryModelService.ts +++ b/src/sql/platform/query/common/queryModelService.ts @@ -90,31 +90,23 @@ export class QueryModelService implements IQueryModelService { (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( TimeElapsedStatusBarItem, - 'status.timeElapsed', - nls.localize('status.timeElapsed', "Time Elapsed"), StatusbarAlignment.RIGHT, 100 /* Should appear to the right of the SQL editor status */ )); (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( RowCountStatusBarItem, - 'status.rowCount', - nls.localize('status.rowCount', "Row Count"), StatusbarAlignment.RIGHT, 100 /* Should appear to the right of the SQL editor status */ )); (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( QueryStatusbarItem, - 'status.query', - nls.localize('status.query', "Query"), StatusbarAlignment.RIGHT, 100 /* High Priority */ )); (platform.Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( SqlFlavorStatusbarItem, - 'status.sqlFlavor', - nls.localize('status.sqlFlavor', "SQL Flavor"), StatusbarAlignment.RIGHT, 90 /* Should appear to the right of the SQL editor status */ )); diff --git a/src/sql/workbench/api/browser/extensionHost.contribution.common.ts b/src/sql/workbench/api/browser/extensionHost.contribution.common.ts deleted file mode 100644 index c9b3d20ef2..0000000000 --- a/src/sql/workbench/api/browser/extensionHost.contribution.common.ts +++ /dev/null @@ -1,23 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import './mainThreadAccountManagement'; -import './mainThreadBackgroundTaskManagement'; -import './mainThreadConnectionManagement'; -import './mainThreadCredentialManagement'; -import './mainThreadDashboard'; -import './mainThreadDashboardWebview'; -import './mainThreadDataProtocol'; -import './mainThreadExtensionManagement'; -import './mainThreadModalDialog'; -import './mainThreadModelView'; -import './mainThreadModelViewDialog'; -import './mainThreadNotebook'; -import './mainThreadNotebookDocumentsAndEditors'; -import './mainThreadObjectExplorer'; -import './mainThreadQueryEditor'; -import './mainThreadResourceProvider'; -import './mainThreadSerializationProvider'; -import './mainThreadTasks'; diff --git a/src/sql/workbench/api/browser/mainThreadDashboard.ts b/src/sql/workbench/api/electron-browser/mainThreadDashboard.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadDashboard.ts rename to src/sql/workbench/api/electron-browser/mainThreadDashboard.ts diff --git a/src/sql/workbench/api/browser/mainThreadModalDialog.ts b/src/sql/workbench/api/electron-browser/mainThreadModalDialog.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadModalDialog.ts rename to src/sql/workbench/api/electron-browser/mainThreadModalDialog.ts diff --git a/src/sql/workbench/api/browser/mainThreadTasks.ts b/src/sql/workbench/api/electron-browser/mainThreadTasks.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadTasks.ts rename to src/sql/workbench/api/electron-browser/mainThreadTasks.ts diff --git a/src/typings/vsda.d.ts b/src/sql/workbench/api/electron-browser/sqlExtensionHost.contribution.ts similarity index 82% rename from src/typings/vsda.d.ts rename to src/sql/workbench/api/electron-browser/sqlExtensionHost.contribution.ts index 5a0ca7212e..91c1b1982b 100644 --- a/src/typings/vsda.d.ts +++ b/src/sql/workbench/api/electron-browser/sqlExtensionHost.contribution.ts @@ -3,8 +3,4 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -declare module 'vsda' { - export class signer { - sign(arg: any): any; - } -} +import 'sql/workbench/api/electron-browser/mainThreadModalDialog'; \ No newline at end of file diff --git a/src/sql/workbench/api/browser/mainThreadAccountManagement.ts b/src/sql/workbench/api/node/mainThreadAccountManagement.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadAccountManagement.ts rename to src/sql/workbench/api/node/mainThreadAccountManagement.ts diff --git a/src/sql/workbench/api/browser/mainThreadBackgroundTaskManagement.ts b/src/sql/workbench/api/node/mainThreadBackgroundTaskManagement.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadBackgroundTaskManagement.ts rename to src/sql/workbench/api/node/mainThreadBackgroundTaskManagement.ts diff --git a/src/sql/workbench/api/browser/mainThreadConnectionManagement.ts b/src/sql/workbench/api/node/mainThreadConnectionManagement.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadConnectionManagement.ts rename to src/sql/workbench/api/node/mainThreadConnectionManagement.ts diff --git a/src/sql/workbench/api/browser/mainThreadCredentialManagement.ts b/src/sql/workbench/api/node/mainThreadCredentialManagement.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadCredentialManagement.ts rename to src/sql/workbench/api/node/mainThreadCredentialManagement.ts diff --git a/src/sql/workbench/api/browser/mainThreadDashboardWebview.ts b/src/sql/workbench/api/node/mainThreadDashboardWebview.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadDashboardWebview.ts rename to src/sql/workbench/api/node/mainThreadDashboardWebview.ts diff --git a/src/sql/workbench/api/browser/mainThreadDataProtocol.ts b/src/sql/workbench/api/node/mainThreadDataProtocol.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadDataProtocol.ts rename to src/sql/workbench/api/node/mainThreadDataProtocol.ts diff --git a/src/sql/workbench/api/browser/mainThreadExtensionManagement.ts b/src/sql/workbench/api/node/mainThreadExtensionManagement.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadExtensionManagement.ts rename to src/sql/workbench/api/node/mainThreadExtensionManagement.ts diff --git a/src/sql/workbench/api/browser/mainThreadModelView.ts b/src/sql/workbench/api/node/mainThreadModelView.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadModelView.ts rename to src/sql/workbench/api/node/mainThreadModelView.ts diff --git a/src/sql/workbench/api/browser/mainThreadModelViewDialog.ts b/src/sql/workbench/api/node/mainThreadModelViewDialog.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadModelViewDialog.ts rename to src/sql/workbench/api/node/mainThreadModelViewDialog.ts diff --git a/src/sql/workbench/api/browser/mainThreadNotebook.ts b/src/sql/workbench/api/node/mainThreadNotebook.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadNotebook.ts rename to src/sql/workbench/api/node/mainThreadNotebook.ts diff --git a/src/sql/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts b/src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadNotebookDocumentsAndEditors.ts rename to src/sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors.ts diff --git a/src/sql/workbench/api/browser/mainThreadObjectExplorer.ts b/src/sql/workbench/api/node/mainThreadObjectExplorer.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadObjectExplorer.ts rename to src/sql/workbench/api/node/mainThreadObjectExplorer.ts diff --git a/src/sql/workbench/api/browser/mainThreadQueryEditor.ts b/src/sql/workbench/api/node/mainThreadQueryEditor.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadQueryEditor.ts rename to src/sql/workbench/api/node/mainThreadQueryEditor.ts diff --git a/src/sql/workbench/api/browser/mainThreadResourceProvider.ts b/src/sql/workbench/api/node/mainThreadResourceProvider.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadResourceProvider.ts rename to src/sql/workbench/api/node/mainThreadResourceProvider.ts diff --git a/src/sql/workbench/api/browser/mainThreadSerializationProvider.ts b/src/sql/workbench/api/node/mainThreadSerializationProvider.ts similarity index 100% rename from src/sql/workbench/api/browser/mainThreadSerializationProvider.ts rename to src/sql/workbench/api/node/mainThreadSerializationProvider.ts diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts index 58bf6d43b0..bb50c5d952 100644 --- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts +++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts @@ -40,7 +40,8 @@ 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 { IURITransformer } from 'vs/base/common/uriIpc'; +import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; +import { AzureResource } from 'sql/platform/accounts/common/interfaces'; import { mssqlProviderName } from 'sql/platform/connection/common/constants'; export interface ISqlExtensionApiFactory { @@ -60,9 +61,10 @@ export function createApiFactory( extensionService: ExtHostExtensionService, logService: ExtHostLogService, extHostStorage: ExtHostStorage, - uriTransformer: IURITransformer | null + schemeTransformer: ISchemeTransformer | null, + outputChannelName: string ): ISqlExtensionApiFactory { - let vsCodeFactory = extHostApi.createApiFactory(initData, rpcProtocol, extHostWorkspace, extHostConfiguration, extensionService, logService, extHostStorage, uriTransformer); + let vsCodeFactory = extHostApi.createApiFactory(initData, rpcProtocol, extHostWorkspace, extHostConfiguration, extensionService, logService, extHostStorage, schemeTransformer, outputChannelName); // Addressable instances const extHostAccountManagement = rpcProtocol.set(SqlExtHostContext.ExtHostAccountManagement, new ExtHostAccountManagement(rpcProtocol)); diff --git a/src/sql/workbench/api/node/sqlExtHost.contribution.ts b/src/sql/workbench/api/node/sqlExtHost.contribution.ts new file mode 100644 index 0000000000..c3795ef7ba --- /dev/null +++ b/src/sql/workbench/api/node/sqlExtHost.contribution.ts @@ -0,0 +1,46 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IWorkbenchContribution, IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; + +// --- SQL contributions +import 'sql/workbench/api/node/mainThreadConnectionManagement'; +import 'sql/workbench/api/node/mainThreadCredentialManagement'; +import 'sql/workbench/api/node/mainThreadDataProtocol'; +import 'sql/workbench/api/node/mainThreadObjectExplorer'; +import 'sql/workbench/api/node/mainThreadBackgroundTaskManagement'; +import 'sql/workbench/api/node/mainThreadSerializationProvider'; +import 'sql/workbench/api/node/mainThreadResourceProvider'; +import 'sql/workbench/api/electron-browser/mainThreadTasks'; +import 'sql/workbench/api/electron-browser/mainThreadDashboard'; +import 'sql/workbench/api/node/mainThreadDashboardWebview'; +import 'sql/workbench/api/node/mainThreadQueryEditor'; +import 'sql/workbench/api/node/mainThreadModelView'; +import 'sql/workbench/api/node/mainThreadModelViewDialog'; +import 'sql/workbench/api/node/mainThreadNotebook'; +import 'sql/workbench/api/node/mainThreadNotebookDocumentsAndEditors'; +import 'sql/workbench/api/node/mainThreadAccountManagement'; +import 'sql/workbench/api/node/mainThreadExtensionManagement'; +import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; + +export class SqlExtHostContribution implements IWorkbenchContribution { + + constructor( + @IInstantiationService private instantiationService: IInstantiationService + ) { + } + + public getId(): string { + return 'sql.api.sqlExtHost'; + } +} + +// Register File Tracker +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution( + SqlExtHostContribution, + LifecyclePhase.Restored +); diff --git a/src/sql/workbench/browser/parts/views/customView.ts b/src/sql/workbench/browser/parts/views/customView.ts index 5bcd1c4053..3fc97e8fe6 100644 --- a/src/sql/workbench/browser/parts/views/customView.ts +++ b/src/sql/workbench/browser/parts/views/customView.ts @@ -14,7 +14,7 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { TreeItemCollapsibleState, ITreeViewDataProvider, TreeViewItemHandleArg, ViewContainer, ITreeItemLabel } from 'vs/workbench/common/views'; import { FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService2 } from 'vs/platform/progress/common/progress'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -160,7 +160,7 @@ export class CustomTreeView extends Disposable implements ITreeView { @IInstantiationService private instantiationService: IInstantiationService, @ICommandService private commandService: ICommandService, @IConfigurationService private configurationService: IConfigurationService, - @IProgressService private progressService: IProgressService + @IProgressService2 private progressService: IProgressService2 ) { super(); this.root = new Root(); @@ -516,7 +516,7 @@ class TreeDataSource implements IDataSource { private treeView: ITreeView, private container: ViewContainer, private id: string, - @IProgressService private progressService: IProgressService, + @IProgressService2 private progressService: IProgressService2, @IOEShimService private objectExplorerService: IOEShimService ) { } diff --git a/src/sql/workbench/electron-browser/modelComponents/diffeditor.component.ts b/src/sql/workbench/electron-browser/modelComponents/diffeditor.component.ts index 0545623ee2..c5b6338d26 100644 --- a/src/sql/workbench/electron-browser/modelComponents/diffeditor.component.ts +++ b/src/sql/workbench/electron-browser/modelComponents/diffeditor.component.ts @@ -18,7 +18,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ComponentBase } from 'sql/workbench/electron-browser/modelComponents/componentBase'; import { IComponent, IComponentDescriptor, IModelStore } from 'sql/workbench/electron-browser/modelComponents/interfaces'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { SimpleLocalProgressService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleProgressService } from 'vs/editor/standalone/browser/simpleServices'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { TextDiffEditor } from 'vs/workbench/browser/parts/editor/textDiffEditor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -70,7 +70,7 @@ export default class DiffEditorComponent extends ComponentBase implements ICompo } private _createEditor(): void { - this._instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleLocalProgressService()])); + this._instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleProgressService()])); this._editor = this._instantiationService.createInstance(TextDiffEditor); this._editor.reverseColoring(); this._editor.create(this._el.nativeElement); diff --git a/src/sql/workbench/electron-browser/modelComponents/editor.component.ts b/src/sql/workbench/electron-browser/modelComponents/editor.component.ts index bace82f53b..a901eb9ae8 100644 --- a/src/sql/workbench/electron-browser/modelComponents/editor.component.ts +++ b/src/sql/workbench/electron-browser/modelComponents/editor.component.ts @@ -21,7 +21,7 @@ import { ComponentBase } from 'sql/workbench/electron-browser/modelComponents/co import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/workbench/electron-browser/modelComponents/interfaces'; import { QueryTextEditor } from 'sql/workbench/electron-browser/modelComponents/queryTextEditor'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { SimpleLocalProgressService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleProgressService } from 'vs/editor/standalone/browser/simpleServices'; import { IProgressService } from 'vs/platform/progress/common/progress'; @Component({ @@ -59,7 +59,7 @@ export default class EditorComponent extends ComponentBase implements IComponent } private _createEditor(): void { - let instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleLocalProgressService()])); + let instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleProgressService()])); this._editor = instantiationService.createInstance(QueryTextEditor); this._editor.create(this._el.nativeElement); this._editor.setVisible(true); diff --git a/src/sql/workbench/parts/connection/browser/connection.contribution.ts b/src/sql/workbench/parts/connection/browser/connection.contribution.ts index 556b5c078c..227bdd3d16 100644 --- a/src/sql/workbench/parts/connection/browser/connection.contribution.ts +++ b/src/sql/workbench/parts/connection/browser/connection.contribution.ts @@ -19,8 +19,6 @@ import { ConnectionStatusbarItem } from 'sql/workbench/parts/connection/browser/ // Register Statusbar item (Registry.as(statusbar.Extensions.Statusbar)).registerStatusbarItem(new statusbar.StatusbarItemDescriptor( ConnectionStatusbarItem, - 'status.connection', - localize('status.connection', "Connection"), StatusbarAlignment.RIGHT, 100 /* High Priority */ )); diff --git a/src/sql/workbench/parts/connection/browser/connectionStatus.ts b/src/sql/workbench/parts/connection/browser/connectionStatus.ts index a8ec25ce1f..8355534d13 100644 --- a/src/sql/workbench/parts/connection/browser/connectionStatus.ts +++ b/src/sql/workbench/parts/connection/browser/connectionStatus.ts @@ -40,7 +40,7 @@ export class ConnectionStatusbarItem implements IStatusbarItem { this._objectExplorerService.onSelectionOrFocusChange(() => this._updateStatus()) ); - return combinedDisposable(...this._toDispose); + return combinedDisposable(this._toDispose); } // Update the connection status shown in the bar diff --git a/src/sql/workbench/parts/connection/common/connectionGlobalStatus.ts b/src/sql/workbench/parts/connection/common/connectionGlobalStatus.ts index 3f846fd3b6..856008d7d1 100644 --- a/src/sql/workbench/parts/connection/common/connectionGlobalStatus.ts +++ b/src/sql/workbench/parts/connection/common/connectionGlobalStatus.ts @@ -3,8 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import { ConnectionSummary } from 'azdata'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import * as LocalizedConstants from 'sql/workbench/parts/connection/common/localizedConstants'; -import { INotificationService } from 'vs/platform/notification/common/notification'; // Status when making connections from the viewlet export class ConnectionGlobalStatus { @@ -12,12 +12,12 @@ export class ConnectionGlobalStatus { private _displayTime: number = 5000; // (in ms) constructor( - @INotificationService private _notificationService: INotificationService + @IStatusbarService private _statusBarService: IStatusbarService ) { } public setStatusToConnected(connectionSummary: ConnectionSummary): void { - if (this._notificationService) { + if (this._statusBarService) { let text: string; let connInfo: string = connectionSummary.serverName; if (connInfo) { @@ -28,13 +28,13 @@ export class ConnectionGlobalStatus { } text = LocalizedConstants.onDidConnectMessage + ' ' + connInfo; } - this._notificationService.status(text, { hideAfter: this._displayTime }); + this._statusBarService.setStatusMessage(text, this._displayTime); } } public setStatusToDisconnected(fileUri: string): void { - if (this._notificationService) { - this._notificationService.status(LocalizedConstants.onDidDisconnectMessage, { hideAfter: this._displayTime }); + if (this._statusBarService) { + this._statusBarService.setStatusMessage(LocalizedConstants.onDidDisconnectMessage, this._displayTime); } } } diff --git a/src/sql/workbench/parts/dashboard/widgets/explorer/explorerTree.ts b/src/sql/workbench/parts/dashboard/widgets/explorer/explorerTree.ts index f0ce1a6454..f7bb8fcb5b 100644 --- a/src/sql/workbench/parts/dashboard/widgets/explorer/explorerTree.ts +++ b/src/sql/workbench/parts/dashboard/widgets/explorer/explorerTree.ts @@ -32,7 +32,7 @@ import { generateUuid } from 'vs/base/common/uuid'; import { $ } from 'vs/base/browser/dom'; import { ExecuteCommandAction } from 'vs/platform/actions/common/actions'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; export class ObjectMetadataWrapper implements ObjectMetadata { public metadataType: MetadataType; @@ -111,7 +111,7 @@ export class ExplorerController extends TreeDefaults.DefaultController { private _contextMenuService: IContextMenuService, private _capabilitiesService: ICapabilitiesService, private _instantiationService: IInstantiationService, - private _progressService: ILocalProgressService + private _progressService: IProgressService ) { super(); } @@ -424,7 +424,7 @@ class ExplorerScriptSelectAction extends ScriptSelectAction { @IQueryEditorService queryEditorService: IQueryEditorService, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, - @ILocalProgressService private progressService: ILocalProgressService + @IProgressService private progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService); } @@ -443,7 +443,7 @@ class ExplorerScriptCreateAction extends ScriptCreateAction { @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, - @ILocalProgressService private progressService: ILocalProgressService + @IProgressService private progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } @@ -462,7 +462,7 @@ class ExplorerScriptAlterAction extends ScriptAlterAction { @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, - @ILocalProgressService private progressService: ILocalProgressService + @IProgressService private progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } @@ -481,7 +481,7 @@ class ExplorerScriptExecuteAction extends ScriptExecuteAction { @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IScriptingService scriptingService: IScriptingService, @IErrorMessageService errorMessageService: IErrorMessageService, - @ILocalProgressService private progressService: ILocalProgressService + @IProgressService private progressService: IProgressService ) { super(id, label, queryEditorService, connectionManagementService, scriptingService, errorMessageService); } @@ -498,7 +498,7 @@ class ExplorerManageAction extends ManageAction { id: string, label: string, @IConnectionManagementService connectionManagementService: IConnectionManagementService, @IAngularEventingService angularEventingService: IAngularEventingService, - @ILocalProgressService private _progressService: ILocalProgressService + @IProgressService private _progressService: IProgressService ) { super(id, label, connectionManagementService, angularEventingService); } diff --git a/src/sql/workbench/parts/dashboard/widgets/explorer/explorerWidget.component.ts b/src/sql/workbench/parts/dashboard/widgets/explorer/explorerWidget.component.ts index ea05edf86e..ff2c11dcca 100644 --- a/src/sql/workbench/parts/dashboard/widgets/explorer/explorerWidget.component.ts +++ b/src/sql/workbench/parts/dashboard/widgets/explorer/explorerWidget.component.ts @@ -7,7 +7,7 @@ import 'vs/css!sql/media/objectTypes/objecttypes'; import 'vs/css!sql/media/icons/common-icons'; import 'vs/css!./media/explorerWidget'; -import { Component, Inject, forwardRef, OnInit, ViewChild, ElementRef } from '@angular/core'; +import { Component, Inject, forwardRef, ChangeDetectorRef, OnInit, ViewChild, ElementRef } from '@angular/core'; import { Router } from '@angular/router'; import { DashboardWidget, IDashboardWidget, WidgetConfig, WIDGET_CONFIG } from 'sql/workbench/parts/dashboard/common/dashboardWidget'; @@ -26,7 +26,7 @@ import { Delayer } from 'vs/base/common/async'; import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; @Component({ @@ -58,6 +58,7 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget, constructor( @Inject(forwardRef(() => CommonServiceInterface)) private _bootstrap: CommonServiceInterface, @Inject(forwardRef(() => Router)) private _router: Router, + @Inject(forwardRef(() => ChangeDetectorRef)) private _changeRef: ChangeDetectorRef, @Inject(WIDGET_CONFIG) protected _config: WidgetConfig, @Inject(forwardRef(() => ElementRef)) private _el: ElementRef, @Inject(IWorkbenchThemeService) private themeService: IWorkbenchThemeService, @@ -65,7 +66,7 @@ export class ExplorerWidget extends DashboardWidget implements IDashboardWidget, @Inject(IInstantiationService) private instantiationService: IInstantiationService, @Inject(IContextMenuService) private contextMenuService: IContextMenuService, @Inject(ICapabilitiesService) private capabilitiesService: ICapabilitiesService, - @Inject(ILocalProgressService) private progressService: ILocalProgressService + @Inject(IProgressService) private progressService: IProgressService ) { super(); this.init(); diff --git a/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts b/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts index 371558c659..1053120c1d 100644 --- a/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts +++ b/src/sql/workbench/parts/dataExplorer/browser/connectionViewletPanel.ts @@ -128,6 +128,7 @@ export class ConnectionViewletPanel extends ViewletPanel { } dispose(): void { + this.disposables = dispose(this.disposables); super.dispose(); } diff --git a/src/sql/workbench/parts/dataExplorer/electron-browser/nodeCommands.ts b/src/sql/workbench/parts/dataExplorer/electron-browser/nodeCommands.ts index 6db9cc1ee7..7e70a2ff5c 100644 --- a/src/sql/workbench/parts/dataExplorer/electron-browser/nodeCommands.ts +++ b/src/sql/workbench/parts/dataExplorer/electron-browser/nodeCommands.ts @@ -12,7 +12,7 @@ import { ICustomViewDescriptor, TreeViewItemHandleArg } from 'sql/workbench/comm import { IQueryEditorService } from 'sql/workbench/services/queryEditor/common/queryEditorService'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IViewsRegistry, Extensions } from 'vs/workbench/common/views'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService2 } from 'vs/platform/progress/common/progress'; import { Registry } from 'vs/platform/registry/common/platform'; export const DISCONNECT_COMMAND_ID = 'dataExplorer.disconnect'; @@ -82,7 +82,7 @@ CommandsRegistry.registerCommand({ CommandsRegistry.registerCommand({ id: REFRESH_COMMAND_ID, handler: (accessor, args: TreeViewItemHandleArg) => { - const progressSerivce = accessor.get(IProgressService); + const progressSerivce = accessor.get(IProgressService2); if (args.$treeItem) { const { treeView } = (Registry.as(Extensions.ViewsRegistry).getView(args.$treeViewId)); if (args.$treeContainerId) { diff --git a/src/sql/workbench/parts/editData/common/editDataInput.ts b/src/sql/workbench/parts/editData/common/editDataInput.ts index aacd37284d..f19cc624a8 100644 --- a/src/sql/workbench/parts/editData/common/editDataInput.ts +++ b/src/sql/workbench/parts/editData/common/editDataInput.ts @@ -56,11 +56,12 @@ export class EditDataInput extends EditorInput implements IConnectableInput { this._setup = false; this._stopButtonEnabled = false; this._refreshButtonEnabled = false; + this._toDispose = []; this._useQueryFilter = false; // re-emit sql editor events through this editor if it exists if (this._sql) { - this._register(this._sql.onDidChangeDirty(() => this._onDidChangeDirty.fire())); + this._toDispose.push(this._sql.onDidChangeDirty(() => this._onDidChangeDirty.fire())); this._sql.disableSaving(); } this.disableSaving(); @@ -73,7 +74,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput { let self = this; // Register callbacks for the Actions - this._register( + this._toDispose.push( this._queryModelService.onRunQueryStart(uri => { if (self.uri === uri) { self.initEditStart(); @@ -81,7 +82,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput { }) ); - this._register( + this._toDispose.push( this._queryModelService.onEditSessionReady((result) => { if (self.uri === result.ownerUri) { self.initEditEnd(result); @@ -209,6 +210,7 @@ export class EditDataInput extends EditorInput implements IConnectableInput { this._queryModelService.disposeQuery(this.uri); this._sql.dispose(); this._results.dispose(); + this._toDispose = dispose(this._toDispose); super.dispose(); } diff --git a/src/sql/workbench/parts/notebook/cellViews/code.component.ts b/src/sql/workbench/parts/notebook/cellViews/code.component.ts index c16ae0d136..f7743f29c7 100644 --- a/src/sql/workbench/parts/notebook/cellViews/code.component.ts +++ b/src/sql/workbench/parts/notebook/cellViews/code.component.ts @@ -17,7 +17,7 @@ import { NotebookModel } from 'sql/workbench/parts/notebook/models/notebookModel import { IColorTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import * as themeColors from 'vs/workbench/common/theme'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { SimpleLocalProgressService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleProgressService } from 'vs/editor/standalone/browser/simpleServices'; import { IProgressService } from 'vs/platform/progress/common/progress'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ITextModel } from 'vs/editor/common/model'; @@ -189,7 +189,7 @@ export class CodeComponent extends AngularDisposable implements OnInit, OnChange } private async createEditor(): Promise { - let instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleLocalProgressService()])); + let instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleProgressService()])); this._editor = instantiationService.createInstance(QueryTextEditor); this._editor.create(this.codeElement.nativeElement); this._editor.setVisible(true); diff --git a/src/sql/workbench/parts/notebook/notebookStyles.ts b/src/sql/workbench/parts/notebook/notebookStyles.ts index 599faa6ca2..2ca4003a37 100644 --- a/src/sql/workbench/parts/notebook/notebookStyles.ts +++ b/src/sql/workbench/parts/notebook/notebookStyles.ts @@ -7,8 +7,8 @@ import 'vs/css!./notebook'; import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { SIDE_BAR_BACKGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, EDITOR_GROUP_HEADER_TABS_BACKGROUND } from 'vs/workbench/common/theme'; import { activeContrastBorder, contrastBorder, buttonBackground, textLinkForeground, textLinkActiveForeground, textPreformatForeground, textBlockQuoteBackground, textBlockQuoteBorder } from 'vs/platform/theme/common/colorRegistry'; +import { IDisposable } from 'vscode-xterm'; import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common/view/editorColorRegistry'; -import { IDisposable } from 'vs/base/common/lifecycle'; export function registerNotebookThemes(overrideEditorThemeSetting: boolean): IDisposable { return registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { diff --git a/src/sql/workbench/parts/objectExplorer/browser/treeSelectionHandler.ts b/src/sql/workbench/parts/objectExplorer/browser/treeSelectionHandler.ts index 7e19f64d6b..46f51eec50 100644 --- a/src/sql/workbench/parts/objectExplorer/browser/treeSelectionHandler.ts +++ b/src/sql/workbench/parts/objectExplorer/browser/treeSelectionHandler.ts @@ -8,7 +8,7 @@ import { ITree } from 'vs/base/parts/tree/browser/tree'; import { ConnectionProfile } from 'sql/platform/connection/common/connectionProfile'; import { IObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService'; -import { IProgressService, IProgressRunner, ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { TreeNode } from 'sql/workbench/parts/objectExplorer/common/treeNode'; import { TreeUpdateUtils } from 'sql/workbench/parts/objectExplorer/browser/treeUpdateUtils'; @@ -18,7 +18,7 @@ export class TreeSelectionHandler { private _clicks: number = 0; private _doubleClickTimeoutTimer: NodeJS.Timer = undefined; - constructor(@ILocalProgressService private _progressService: ILocalProgressService) { + constructor(@IProgressService private _progressService: IProgressService) { } diff --git a/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts b/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts index e05e45e648..2146077d7f 100644 --- a/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts +++ b/src/sql/workbench/parts/profiler/browser/profilerTableEditor.ts @@ -271,7 +271,7 @@ export class ProfilerTableEditor extends BaseEditor implements IProfilerControll : localize('ProfilerTableEditor.eventCount', 'Events: {0}', this._input.data.getLength()); this._disposeStatusbarItem(); - this._statusbarItem = this._statusbarService.addEntry({ text: message }, 'status.eventCount', localize('status.eventCount', "Event Count"), StatusbarAlignment.RIGHT); + this._statusbarItem = this._statusbarService.addEntry({ text: message }, StatusbarAlignment.RIGHT); } } diff --git a/src/sql/workbench/parts/query/browser/flavorStatus.ts b/src/sql/workbench/parts/query/browser/flavorStatus.ts index 5eb5e19fd6..624bf86893 100644 --- a/src/sql/workbench/parts/query/browser/flavorStatus.ts +++ b/src/sql/workbench/parts/query/browser/flavorStatus.ts @@ -87,7 +87,7 @@ export class SqlFlavorStatusbarItem implements IStatusbarItem { this._editorService.onDidVisibleEditorsChange(() => this._onEditorsChanged()), this._editorService.onDidCloseEditor(event => this._onEditorClosed(event)) ); - return combinedDisposable(...this._toDispose); + return combinedDisposable(this._toDispose); } private _onSelectionClick() { diff --git a/src/sql/workbench/parts/query/browser/queryEditor.ts b/src/sql/workbench/parts/query/browser/queryEditor.ts index c9c7782940..e377c37bb2 100644 --- a/src/sql/workbench/parts/query/browser/queryEditor.ts +++ b/src/sql/workbench/parts/query/browser/queryEditor.ts @@ -156,7 +156,7 @@ export class QueryEditor extends BaseEditor { this.setTaskbarContent(); - this._register(this.configurationService.onDidChangeConfiguration(e => { + this._toDispose.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectedKeys.includes('workbench.enablePreviewFeatures')) { this.setTaskbarContent(); } diff --git a/src/sql/workbench/parts/query/browser/queryStatus.ts b/src/sql/workbench/parts/query/browser/queryStatus.ts index fcb5311d8d..a4785963e5 100644 --- a/src/sql/workbench/parts/query/browser/queryStatus.ts +++ b/src/sql/workbench/parts/query/browser/queryStatus.ts @@ -47,7 +47,7 @@ export class QueryStatusbarItem implements IStatusbarItem { this._editorService.onDidCloseEditor(event => this._onEditorClosed(event)) ); - return combinedDisposable(...this._toDispose); + return combinedDisposable(this._toDispose); } private _onEditorClosed(event: IEditorCloseEvent): void { diff --git a/src/sql/workbench/parts/query/browser/rowCountStatus.ts b/src/sql/workbench/parts/query/browser/rowCountStatus.ts index 38a9b72187..f781963087 100644 --- a/src/sql/workbench/parts/query/browser/rowCountStatus.ts +++ b/src/sql/workbench/parts/query/browser/rowCountStatus.ts @@ -40,7 +40,7 @@ export class RowCountStatusBarItem implements IStatusbarItem { this._showStatus(); - return combinedDisposable(...disposables); + return combinedDisposable(disposables); } private _onEditorsChanged() { diff --git a/src/sql/workbench/parts/query/browser/timeElapsedStatus.ts b/src/sql/workbench/parts/query/browser/timeElapsedStatus.ts index cd03216e35..43a1238796 100644 --- a/src/sql/workbench/parts/query/browser/timeElapsedStatus.ts +++ b/src/sql/workbench/parts/query/browser/timeElapsedStatus.ts @@ -43,7 +43,7 @@ export class TimeElapsedStatusBarItem implements IStatusbarItem { this._showStatus(); - return combinedDisposable(...disposables); + return combinedDisposable(disposables); } private _onEditorsChanged() { diff --git a/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts b/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts index ec9226402d..81b7bf2a0a 100644 --- a/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts +++ b/src/sql/workbench/services/accountManagement/browser/accountManagementService.ts @@ -69,8 +69,6 @@ export class AccountManagementService implements IAccountManagementService { // Register status bar item let statusbarDescriptor = new statusbar.StatusbarItemDescriptor( AccountListStatusbarItem, - 'status.accountList', - localize('status.accountList', "Account List"), StatusbarAlignment.LEFT, 15000 /* Highest Priority */ ); diff --git a/src/sql/workbench/services/commandLine/common/commandLineService.ts b/src/sql/workbench/services/commandLine/common/commandLineService.ts index d65717cc5a..2558f0fcdd 100644 --- a/src/sql/workbench/services/commandLine/common/commandLineService.ts +++ b/src/sql/workbench/services/commandLine/common/commandLineService.ts @@ -22,11 +22,11 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { ipcRenderer as ipc } from 'electron'; import { IConnectionProfile } from 'sql/platform/connection/common/interfaces'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { localize } from 'vs/nls'; import { QueryInput } from 'sql/workbench/parts/query/common/queryInput'; import { URI } from 'vs/base/common/uri'; import { ILogService } from 'vs/platform/log/common/log'; -import { INotificationService } from 'vs/platform/notification/common/notification'; export class CommandLineService implements ICommandLineProcessing { public _serviceBrand: any; @@ -40,7 +40,7 @@ export class CommandLineService implements ICommandLineProcessing { @IEditorService private _editorService: IEditorService, @ICommandService private _commandService: ICommandService, @IConfigurationService private _configurationService: IConfigurationService, - @INotificationService private _notificationService: INotificationService, + @IStatusbarService private _statusBarService: IStatusbarService, @ILogService private logService: ILogService ) { if (ipc) { @@ -92,8 +92,8 @@ export class CommandLineService implements ICommandLineProcessing { } let connectedContext: azdata.ConnectedContext = undefined; if (profile) { - if (this._notificationService) { - this._notificationService.status(localize('connectingLabel', 'Connecting: {0}', profile.serverName), { hideAfter: 2500 }); + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('connectingLabel', 'Connecting:') + profile.serverName, 2500); } try { await this._connectionManagementService.connectIfNotConnected(profile, 'connection', true); @@ -106,8 +106,8 @@ export class CommandLineService implements ICommandLineProcessing { } } if (commandName) { - if (this._notificationService) { - this._notificationService.status(localize('runningCommandLabel', 'Running command: {0}', commandName), { hideAfter: 2500 }); + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('runningCommandLabel', 'Running command:') + commandName, 2500); } await this._commandService.executeCommand(commandName, connectedContext); } else if (profile) { @@ -119,8 +119,8 @@ export class CommandLineService implements ICommandLineProcessing { } else { // Default to showing new query - if (this._notificationService) { - this._notificationService.status(localize('openingNewQueryLabel', 'Opening new query: {0}', profile.serverName), { hideAfter: 2500 }); + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('openingNewQueryLabel', 'Opening new query:') + profile.serverName, 2500); } try { await TaskUtilities.newQuery(profile, @@ -150,8 +150,8 @@ export class CommandLineService implements ICommandLineProcessing { showConnectionDialogOnError: warnOnConnectFailure, showFirewallRuleOnError: warnOnConnectFailure }; - if (this._notificationService) { - this._notificationService.status(localize('connectingQueryLabel', 'Connecting query file'), { hideAfter: 2500 }); + if (this._statusBarService) { + this._statusBarService.setStatusMessage(localize('connectingQueryLabel', 'Connecting query file'), 2500); } await this._connectionManagementService.connect(profile, uriString, options); } diff --git a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts index 0d5a0d9397..5e103556da 100644 --- a/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts +++ b/src/sql/workbench/services/connection/browser/connectionDialogWidget.ts @@ -451,6 +451,10 @@ export class ConnectionDialogWidget extends Modal { this.onProviderTypeSelected(displayName); } + public dispose(): void { + this._toDispose.forEach(obj => obj.dispose()); + } + public set databaseDropdownExpanded(val: boolean) { this._databaseDropdownExpanded = val; } diff --git a/src/sql/workbench/services/insights/test/common/insightsUtils.test.ts b/src/sql/workbench/services/insights/test/common/insightsUtils.test.ts index 3fc9de5f46..6fd373643e 100644 --- a/src/sql/workbench/services/insights/test/common/insightsUtils.test.ts +++ b/src/sql/workbench/services/insights/test/common/insightsUtils.test.ts @@ -45,8 +45,7 @@ class TestEnvironmentService implements IWorkbenchEnvironmentService { appNameLong: string; appQuality?: string; appSettingsHome: string; - - settingsResource: URI; + appSettingsPath: string; appKeybindingsPath: string; settingsSearchBuildId?: number; settingsSearchUrl?: string; diff --git a/src/sqltest/workbench/api/extHostAccountManagement.test.ts b/src/sqltest/workbench/api/extHostAccountManagement.test.ts index 7d1b613e0e..d09743d523 100644 --- a/src/sqltest/workbench/api/extHostAccountManagement.test.ts +++ b/src/sqltest/workbench/api/extHostAccountManagement.test.ts @@ -12,7 +12,7 @@ import { TestRPCProtocol } from 'vs/workbench/test/electron-browser/api/testRPCP import { TestInstantiationService } from 'vs/platform/instantiation/test/common/instantiationServiceMock'; import { IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import { SqlMainContext } from 'sql/workbench/api/node/sqlExtHost.protocol'; -import { MainThreadAccountManagement } from 'sql/workbench/api/browser/mainThreadAccountManagement'; +import { MainThreadAccountManagement } from 'sql/workbench/api/node/mainThreadAccountManagement'; import { IAccountManagementService, AzureResource } from 'sql/platform/accounts/common/interfaces'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; diff --git a/src/sqltest/workbench/api/extHostCredentialManagement.test.ts b/src/sqltest/workbench/api/extHostCredentialManagement.test.ts index a6a7d3c5fa..9668980dab 100644 --- a/src/sqltest/workbench/api/extHostCredentialManagement.test.ts +++ b/src/sqltest/workbench/api/extHostCredentialManagement.test.ts @@ -9,7 +9,7 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { ExtHostCredentialManagement } from 'sql/workbench/api/node/extHostCredentialManagement'; import { SqlMainContext } from 'sql/workbench/api/node/sqlExtHost.protocol'; import { IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; -import { MainThreadCredentialManagement } from 'sql/workbench/api/browser/mainThreadCredentialManagement'; +import { MainThreadCredentialManagement } from 'sql/workbench/api/node/mainThreadCredentialManagement'; import { CredentialsTestProvider, CredentialsTestService } from 'sqltest/stubs/credentialsTestStubs'; import { ICredentialsService } from 'sql/platform/credentials/common/credentialsService'; import { Credential, CredentialProvider } from 'azdata'; diff --git a/src/sqltest/workbench/api/mainThreadBackgroundTaskManagement.test.ts b/src/sqltest/workbench/api/mainThreadBackgroundTaskManagement.test.ts index 656039a6a6..078d66771a 100644 --- a/src/sqltest/workbench/api/mainThreadBackgroundTaskManagement.test.ts +++ b/src/sqltest/workbench/api/mainThreadBackgroundTaskManagement.test.ts @@ -5,7 +5,7 @@ import * as azdata from 'azdata'; import { Mock, It, Times } from 'typemoq'; -import { MainThreadBackgroundTaskManagement, TaskStatus } from 'sql/workbench/api/browser/mainThreadBackgroundTaskManagement'; +import { MainThreadBackgroundTaskManagement, TaskStatus } from 'sql/workbench/api/node/mainThreadBackgroundTaskManagement'; import { ExtHostBackgroundTaskManagementShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; import { ITaskService } from 'sql/platform/tasks/common/tasksService'; import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; diff --git a/src/sqltest/workbench/api/mainThreadModelViewDialog.test.ts b/src/sqltest/workbench/api/mainThreadModelViewDialog.test.ts index 694461c91b..5d3676eef9 100644 --- a/src/sqltest/workbench/api/mainThreadModelViewDialog.test.ts +++ b/src/sqltest/workbench/api/mainThreadModelViewDialog.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { Mock, It, Times } from 'typemoq'; -import { MainThreadModelViewDialog } from 'sql/workbench/api/browser/mainThreadModelViewDialog'; +import { MainThreadModelViewDialog } from 'sql/workbench/api/node/mainThreadModelViewDialog'; import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { IModelViewButtonDetails, IModelViewTabDetails, IModelViewDialogDetails, IModelViewWizardPageDetails, IModelViewWizardDetails, DialogMessage, MessageLevel } from 'sql/workbench/api/common/sqlExtHostTypes'; import { CustomDialogService } from 'sql/platform/dialog/customDialogService'; diff --git a/src/sqltest/workbench/api/mainThreadNotebook.test.ts b/src/sqltest/workbench/api/mainThreadNotebook.test.ts index 94878a0451..45f039684f 100644 --- a/src/sqltest/workbench/api/mainThreadNotebook.test.ts +++ b/src/sqltest/workbench/api/mainThreadNotebook.test.ts @@ -12,7 +12,7 @@ import { URI, UriComponents } from 'vs/base/common/uri'; import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; import { ExtHostNotebookShape } from 'sql/workbench/api/node/sqlExtHost.protocol'; -import { MainThreadNotebook } from 'sql/workbench/api/browser/mainThreadNotebook'; +import { MainThreadNotebook } from 'sql/workbench/api/node/mainThreadNotebook'; import { NotebookService } from 'sql/workbench/services/notebook/common/notebookServiceImpl'; import { INotebookProvider } from 'sql/workbench/services/notebook/common/notebookService'; import { INotebookManagerDetails, INotebookSessionDetails, INotebookKernelDetails, INotebookFutureDetails } from 'sql/workbench/api/common/sqlExtHostTypes'; diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index 59163a017c..20e58bcd73 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 4.2.3 +// Type definitions for Electron 3.1.8 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -86,7 +86,7 @@ declare namespace Electron { webviewTag: WebviewTag; } - interface AllElectron extends MainInterface, RendererInterface { } + interface AllElectron extends MainInterface, RendererInterface {} const app: App; const autoUpdater: AutoUpdater; @@ -119,7 +119,7 @@ declare namespace Electron { interface App extends EventEmitter { - // Docs: http://electronjs.org/docs/api/app + // Docs: http://electron.atom.io/docs/api/app /** * Emitted when Chrome's accessibility support changes. This event fires when @@ -472,100 +472,6 @@ declare namespace Electron { once(event: 'ready', listener: (launchInfo: any) => void): this; addListener(event: 'ready', listener: (launchInfo: any) => void): this; removeListener(event: 'ready', listener: (launchInfo: any) => void): this; - /** - * Emitted when remote.getBuiltin() is called in the renderer process of - * webContents. Calling event.preventDefault() will prevent the module from being - * returned. Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - once(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - addListener(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - removeListener(event: 'remote-get-builtin', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - /** - * Emitted when remote.getCurrentWebContents() is called in the renderer process of - * webContents. Calling event.preventDefault() will prevent the object from being - * returned. Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'remote-get-current-web-contents', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted when remote.getCurrentWindow() is called in the renderer process of - * webContents. Calling event.preventDefault() will prevent the object from being - * returned. Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - once(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - addListener(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - removeListener(event: 'remote-get-current-window', listener: (event: Event, - webContents: WebContents) => void): this; - /** - * Emitted when remote.getGlobal() is called in the renderer process of - * webContents. Calling event.preventDefault() will prevent the global from being - * returned. Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - once(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - addListener(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - removeListener(event: 'remote-get-global', listener: (event: Event, - webContents: WebContents, - globalName: string) => void): this; - /** - * Emitted when .getWebContents() is called in the renderer process of - * webContents. Calling event.preventDefault() will prevent the object from being - * returned. Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-guest-web-contents', listener: (event: Event, - webContents: WebContents, - guestWebContents: WebContents) => void): this; - once(event: 'remote-get-guest-web-contents', listener: (event: Event, - webContents: WebContents, - guestWebContents: WebContents) => void): this; - addListener(event: 'remote-get-guest-web-contents', listener: (event: Event, - webContents: WebContents, - guestWebContents: WebContents) => void): this; - removeListener(event: 'remote-get-guest-web-contents', listener: (event: Event, - webContents: WebContents, - guestWebContents: WebContents) => void): this; - /** - * Emitted when remote.require() is called in the renderer process of webContents. - * Calling event.preventDefault() will prevent the module from being returned. - * Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - once(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - addListener(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; - removeListener(event: 'remote-require', listener: (event: Event, - webContents: WebContents, - moduleName: string) => void): this; /** * This event will be emitted inside the primary instance of your application when * a second instance has been executed. argv is an Array of the second instance's @@ -784,11 +690,6 @@ declare namespace Electron { * is ready. */ enableMixedSandbox(): void; - /** - * Enables full sandbox mode on the app. This method can only be called before app - * is ready. - */ - enableSandbox(): void; /** * Exits immediately with exitCode. exitCode defaults to 0. All windows will be * closed immediately without asking user and the before-quit and will-quit events @@ -808,22 +709,13 @@ declare namespace Electron { * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux * and macOS, icons depend on the application associated with file mime type. */ - getFileIcon(path: string, callback: (error: Error, icon: NativeImage) => void): void; + getFileIcon(path: string, options: FileIconOptions, callback: (error: Error, icon: NativeImage) => void): void; /** * Fetches a path's associated icon. On Windows, there a 2 kinds of icons: On Linux * and macOS, icons depend on the application associated with file mime type. */ - getFileIcon(path: string, options: FileIconOptions, callback: (error: Error, icon: NativeImage) => void): void; + getFileIcon(path: string, callback: (error: Error, icon: NativeImage) => void): void; getGPUFeatureStatus(): GPUFeatureStatus; - /** - * For infoType equal to complete: Promise is fulfilled with Object containing all - * the GPU Information as in chromium's GPUInfo object. This includes the version - * and driver information that's shown on chrome://gpu page. For infoType equal to - * basic: Promise is fulfilled with Object containing fewer attributes than when - * requested with complete. Here's an example of basic response: Using basic should - * be preferred if only basic information like vendorId or driverId is needed. - */ - getGPUInfo(infoType: string): Promise; getJumpListSettings(): JumpListSettings; /** * To set the locale, you'll want to use a command line switch at app startup, @@ -862,7 +754,7 @@ declare namespace Electron { /** * Imports the certificate in pkcs12 format into the platform certificate store. * callback is called with the result of import operation, a value of 0 indicates - * success while any other value indicates failure according to Chromium + * success while any other value indicates failure according to chromium * net_error_list. */ importCertificate(options: ImportCertificateOptions, callback: (result: number) => void): void; @@ -951,9 +843,9 @@ declare namespace Electron { setAboutPanelOptions(options: AboutPanelOptionsOptions): void; /** * Manually enables Chrome's accessibility support, allowing to expose - * accessibility switch to users in application settings. See Chromium's - * accessibility docs for more details. Disabled by default. This API must be - * called after the ready event is emitted. Note: Rendering accessibility tree can + * accessibility switch to users in application settings. + * https://www.chromium.org/developers/design-documents/accessibility for more + * details. Disabled by default. Note: Rendering accessibility tree can * significantly affect the performance of your app. It should not be enabled by * default. */ @@ -1037,12 +929,7 @@ declare namespace Electron { */ show(): void; /** - * Show the about panel with the values defined in the app's .plist file or with - * the options set via app.setAboutPanelOptions(options). - */ - showAboutPanel(): void; - /** - * Start accessing a security scoped resource. With this method Electron + * Start accessing a security scoped resource. With this method electron * applications that are packaged for the Mac App Store may reach outside their * sandbox to access files chosen by the user. See Apple's documentation for a * description of how this system works. @@ -1053,7 +940,7 @@ declare namespace Electron { * userInfo into its current userInfo dictionary. */ updateCurrentActivity(type: string, userInfo: any): void; - whenReady(): Promise; + whenReady(): Promise; commandLine: CommandLine; dock: Dock; /** @@ -1062,19 +949,11 @@ declare namespace Electron { * production environments. */ isPackaged?: boolean; - /** - * A String which is the user agent string Electron will use as a global fallback. - * This is the user agent that will be used when no user agent is set at the - * webContents or session level. Useful for ensuring your entire app has the same - * user agent. Set to a custom value as early as possible in your apps - * initialization to ensure that your overridden value is used. - */ - userAgentFallback?: string; } interface AutoUpdater extends EventEmitter { - // Docs: http://electronjs.org/docs/api/auto-updater + // Docs: http://electron.atom.io/docs/api/auto-updater /** * This event is emitted after a user calls quitAndInstall(). When this API is @@ -1111,9 +990,7 @@ declare namespace Electron { removeListener(event: 'update-available', listener: Function): this; /** * Emitted when an update has been downloaded. On Windows only releaseName is - * available. Note: It is not strictly necessary to handle this event. A - * successfully downloaded update will still be applied the next time the - * application starts. + * available. */ on(event: 'update-downloaded', listener: (event: Event, releaseNotes: string, @@ -1152,10 +1029,10 @@ declare namespace Electron { * Restarts the app and installs the update after it has been downloaded. It should * only be called after update-downloaded has been emitted. Under the hood calling * autoUpdater.quitAndInstall() will close all application windows first, and - * automatically call app.quit() after all windows have been closed. Note: It is - * not strictly necessary to call this function to apply an update, as a - * successfully downloaded update will always be applied the next time the - * application starts. + * automatically call app.quit() after all windows have been closed. Note: If the + * application is quit without calling this API after the update-downloaded event + * has been emitted, the application will still be replaced by the updated one on + * the next run. */ quitAndInstall(): void; /** @@ -1166,7 +1043,7 @@ declare namespace Electron { interface BluetoothDevice { - // Docs: http://electronjs.org/docs/api/structures/bluetooth-device + // Docs: http://electron.atom.io/docs/api/structures/bluetooth-device deviceId: string; deviceName: string; @@ -1174,11 +1051,11 @@ declare namespace Electron { class BrowserView extends EventEmitter { - // Docs: http://electronjs.org/docs/api/browser-view + // Docs: http://electron.atom.io/docs/api/browser-view constructor(options?: BrowserViewConstructorOptions); static fromId(id: number): BrowserView; - static fromWebContents(webContents: WebContents): (BrowserView) | (null); + static fromWebContents(webContents: WebContents): BrowserView | null; static getAllViews(): BrowserView[]; /** * Force closing the view, the unload and beforeunload events won't be emitted for @@ -1199,19 +1076,8 @@ declare namespace Electron { class BrowserWindow extends EventEmitter { - // Docs: http://electronjs.org/docs/api/browser-window + // Docs: http://electron.atom.io/docs/api/browser-window - /** - * Emitted when the window is set or unset to show always on top of other windows. - */ - on(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - once(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - addListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; - removeListener(event: 'always-on-top-changed', listener: (event: Event, - isAlwaysOnTop: boolean) => void): this; /** * Emitted when an App Command is invoked. These are typically related to keyboard * media keys or browser commands, as well as the "Back" button built into some @@ -1341,13 +1207,13 @@ declare namespace Electron { * prevent the native window's title from changing. */ on(event: 'page-title-updated', listener: (event: Event, - title: string, explicitSet: boolean) => void): this; + title: string) => void): this; once(event: 'page-title-updated', listener: (event: Event, - title: string, explicitSet: boolean) => void): this; + title: string) => void): this; addListener(event: 'page-title-updated', listener: (event: Event, - title: string, explicitSet: boolean) => void): this; + title: string) => void): this; removeListener(event: 'page-title-updated', listener: (event: Event, - title: string, explicitSet: boolean) => void): this; + title: string) => void): this; /** * Emitted when the web page has been rendered (while not being shown) and window * can be displayed without a visual flash. @@ -1357,7 +1223,7 @@ declare namespace Electron { addListener(event: 'ready-to-show', listener: Function): this; removeListener(event: 'ready-to-show', listener: Function): this; /** - * Emitted after the window has been resized. + * Emitted when the window is being resized. */ on(event: 'resize', listener: Function): this; once(event: 'resize', listener: Function): this; @@ -1452,58 +1318,6 @@ declare namespace Electron { once(event: 'unresponsive', listener: Function): this; addListener(event: 'unresponsive', listener: Function): this; removeListener(event: 'unresponsive', listener: Function): this; - /** - * Emitted before the window is moved. Calling event.preventDefault() will prevent - * the window from being moved. Note that this is only emitted when the window is - * being resized manually. Resizing the window with setBounds/setSize will not emit - * this event. - */ - on(event: 'will-move', listener: (event: Event, - /** - * ` Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - once(event: 'will-move', listener: (event: Event, - /** - * ` Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - addListener(event: 'will-move', listener: (event: Event, - /** - * ` Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - removeListener(event: 'will-move', listener: (event: Event, - /** - * ` Location the window is being moved to. - */ - newBounds: Rectangle) => void): this; - /** - * Emitted before the window is resized. Calling event.preventDefault() will - * prevent the window from being resized. Note that this is only emitted when the - * window is being resized manually. Resizing the window with setBounds/setSize - * will not emit this event. - */ - on(event: 'will-resize', listener: (event: Event, - /** - * ` Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - once(event: 'will-resize', listener: (event: Event, - /** - * ` Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - addListener(event: 'will-resize', listener: (event: Event, - /** - * ` Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; - removeListener(event: 'will-resize', listener: (event: Event, - /** - * ` Size the window is being resized to. - */ - newBounds: Rectangle) => void): this; constructor(options?: BrowserWindowConstructorOptions); /** * Adds DevTools extension located at path, and returns extension's name. The @@ -1521,7 +1335,7 @@ declare namespace Electron { * This API cannot be called before the ready event of the app module is emitted. */ static addExtension(path: string): void; - static fromBrowserView(browserView: BrowserView): (BrowserWindow) | (null); + static fromBrowserView(browserView: BrowserView): BrowserWindow | null; static fromId(id: number): BrowserWindow; static fromWebContents(webContents: WebContents): BrowserWindow; static getAllWindows(): BrowserWindow[]; @@ -1535,7 +1349,7 @@ declare namespace Electron { * emitted. */ static getExtensions(): Extensions; - static getFocusedWindow(): (BrowserWindow) | (null); + static getFocusedWindow(): BrowserWindow | null; /** * Remove a DevTools extension by name. Note: This API cannot be called before the * ready event of the app module is emitted. @@ -1597,7 +1411,7 @@ declare namespace Electron { * Note: The BrowserView API is currently experimental and may change or be removed * in future Electron releases. */ - getBrowserView(): (BrowserView) | (null); + getBrowserView(): BrowserView | null; getChildWindows(): BrowserWindow[]; getContentBounds(): Rectangle; getContentSize(): number[]; @@ -1608,13 +1422,6 @@ declare namespace Electron { * (unsigned long) on Linux. */ getNativeWindowHandle(): Buffer; - /** - * Note: whatever the current state of the window : maximized, minimized or in - * fullscreen, this function always returns the position and size of the window in - * normal state. In normal state, getBounds and getNormalBounds returns the same - * Rectangle. - */ - getNormalBounds(): Rectangle; getOpacity(): number; getParentWindow(): BrowserWindow; getPosition(): number[]; @@ -1666,7 +1473,6 @@ declare namespace Electron { * On Linux always returns true. */ isMovable(): boolean; - isNormal(): boolean; isResizable(): boolean; isSimpleFullScreen(): boolean; isVisible(): boolean; @@ -1679,7 +1485,7 @@ declare namespace Electron { * Same as webContents.loadFile, filePath should be a path to an HTML file relative * to the root of your application. See the webContents docs for more information. */ - loadFile(filePath: string, options?: LoadFileOptions): void; + loadFile(filePath: string): void; /** * Same as webContents.loadURL(url[, options]). The url can be a remote address * (e.g. http://) or a path to a local HTML file using the file:// protocol. To @@ -1773,12 +1579,7 @@ declare namespace Electron { */ setAutoHideMenuBar(hide: boolean): void; /** - * Sets the background color of the window. See Setting backgroundColor. - */ - setBackgroundColor(backgroundColor: string): void; - /** - * Resizes and moves the window to the supplied bounds. Any properties that are not - * supplied will default to their current values. + * Resizes and moves the window to the supplied bounds */ setBounds(bounds: Rectangle, animate?: boolean): void; setBrowserView(browserView: BrowserView): void; @@ -1854,7 +1655,7 @@ declare namespace Electron { * Sets the menu as the window's menu bar, setting it to null will remove the menu * bar. */ - setMenu(menu: (Menu) | (null)): void; + setMenu(menu: Menu | null): void; /** * Sets whether the menu bar should be visible. If the menu bar is auto-hide, users * can still bring up the menu bar by pressing the single Alt key. @@ -1881,7 +1682,7 @@ declare namespace Electron { * Sets a 16 x 16 pixel overlay onto the current taskbar icon, usually used to * convey some sort of application status or to passively notify the user. */ - setOverlayIcon(overlay: (NativeImage) | (null), description: string): void; + setOverlayIcon(overlay: NativeImage | null, description: string): void; /** * Sets parent as current window's parent window, passing null will turn current * window into a top-level window. @@ -1953,8 +1754,7 @@ declare namespace Electron { /** * Sets the region of the window to show as the thumbnail image displayed when * hovering over the window in the taskbar. You can reset the thumbnail to be the - * entire window by specifying an empty region: { x: 0, y: 0, width: 0, height: 0 - * }. + * entire window by specifying an empty region: {x: 0, y: 0, width: 0, height: 0}. */ setThumbnailClip(region: Rectangle): void; /** @@ -1982,12 +1782,7 @@ declare namespace Electron { * Sets whether the window should be visible on all workspaces. Note: This API does * nothing on Windows. */ - setVisibleOnAllWorkspaces(visible: boolean, options?: VisibleOnAllWorkspacesOptions): void; - /** - * Sets whether the window traffic light buttons should be visible. This cannot be - * called when titleBarStyle is set to customButtonsOnHover. - */ - setWindowButtonVisibility(visible: boolean): void; + setVisibleOnAllWorkspaces(visible: boolean): void; /** * Shows and gives focus to the window. */ @@ -2023,7 +1818,7 @@ declare namespace Electron { class BrowserWindowProxy extends EventEmitter { - // Docs: http://electronjs.org/docs/api/browser-window-proxy + // Docs: http://electron.atom.io/docs/api/browser-window-proxy /** * Removes focus from the child window. @@ -2056,7 +1851,7 @@ declare namespace Electron { interface Certificate { - // Docs: http://electronjs.org/docs/api/structures/certificate + // Docs: http://electron.atom.io/docs/api/structures/certificate /** * PEM encoded data @@ -2102,37 +1897,37 @@ declare namespace Electron { interface CertificatePrincipal { - // Docs: http://electronjs.org/docs/api/structures/certificate-principal + // Docs: http://electron.atom.io/docs/api/structures/certificate-principal /** - * Common Name. + * Common Name */ commonName: string; /** - * Country or region. + * Country or region */ country: string; /** - * Locality. + * Locality */ locality: string; /** - * Organization names. + * Organization names */ organizations: string[]; /** - * Organization Unit names. + * Organization Unit names */ organizationUnits: string[]; /** - * State or province. + * State or province */ state: string; } class ClientRequest extends EventEmitter { - // Docs: http://electronjs.org/docs/api/client-request + // Docs: http://electron.atom.io/docs/api/client-request /** * Emitted when the request is aborted. The abort event will not be fired if the @@ -2250,7 +2045,7 @@ declare namespace Electron { * Sends the last chunk of the request data. Subsequent write or end operations * will not be allowed. The finish event is emitted just after the end operation. */ - end(chunk?: (string) | (Buffer), encoding?: string, callback?: Function): void; + end(chunk?: string | Buffer, encoding?: string, callback?: Function): void; /** * Continues any deferred redirection request when the redirection mode is manual. */ @@ -2283,13 +2078,13 @@ declare namespace Electron { * issued on the wire. After the first write operation, it is not allowed to add or * remove a custom header. */ - write(chunk: (string) | (Buffer), encoding?: string, callback?: Function): void; + write(chunk: string | Buffer, encoding?: string, callback?: Function): void; chunkedEncoding: boolean; } interface Clipboard extends EventEmitter { - // Docs: http://electronjs.org/docs/api/clipboard + // Docs: http://electron.atom.io/docs/api/clipboard availableFormats(type?: string): string[]; /** @@ -2349,7 +2144,7 @@ declare namespace Electron { interface ContentTracing extends EventEmitter { - // Docs: http://electronjs.org/docs/api/content-tracing + // Docs: http://electron.atom.io/docs/api/content-tracing /** * Get the current monitoring traced data. Child processes typically cache trace @@ -2386,7 +2181,7 @@ declare namespace Electron { * request. The callback will be called once all child processes have acknowledged * the startRecording request. */ - startRecording(options: (TraceCategoriesAndOptions) | (TraceConfig), callback: Function): void; + startRecording(options: TraceCategoriesAndOptions | TraceConfig, callback: Function): void; /** * Stop monitoring on all processes. Once all child processes have acknowledged the * stopMonitoring request the callback is called. @@ -2408,11 +2203,10 @@ declare namespace Electron { interface Cookie { - // Docs: http://electronjs.org/docs/api/structures/cookie + // Docs: http://electron.atom.io/docs/api/structures/cookie /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. + * The domain of the cookie. */ domain?: string; /** @@ -2421,8 +2215,7 @@ declare namespace Electron { */ expirationDate?: number; /** - * Whether the cookie is a host-only cookie; this will only be true if no domain - * was passed. + * Whether the cookie is a host-only cookie. */ hostOnly?: boolean; /** @@ -2454,7 +2247,7 @@ declare namespace Electron { class Cookies extends EventEmitter { - // Docs: http://electronjs.org/docs/api/cookies + // Docs: http://electron.atom.io/docs/api/cookies /** * Emitted when a cookie is changed because it was added, edited, removed, or @@ -2535,7 +2328,7 @@ declare namespace Electron { interface CPUUsage { - // Docs: http://electronjs.org/docs/api/structures/cpu-usage + // Docs: http://electron.atom.io/docs/api/structures/cpu-usage /** * The number of average idle cpu wakeups per second since the last call to @@ -2550,7 +2343,7 @@ declare namespace Electron { interface CrashReport { - // Docs: http://electronjs.org/docs/api/structures/crash-report + // Docs: http://electron.atom.io/docs/api/structures/crash-report date: Date; id: string; @@ -2558,7 +2351,7 @@ declare namespace Electron { interface CrashReporter extends EventEmitter { - // Docs: http://electronjs.org/docs/api/crash-reporter + // Docs: http://electron.atom.io/docs/api/crash-reporter /** * Set an extra parameter to be sent with the crash report. The values specified @@ -2569,10 +2362,8 @@ declare namespace Electron { */ addExtraParameter(key: string, value: string): void; /** - * Returns the date and ID of the last crash report. Only crash reports that have - * been uploaded will be returned; even if a crash report is present on disk it - * will not be returned until it is uploaded. In the case that there are no - * uploaded reports, null is returned. + * Returns the date and ID of the last crash report. If no crash reports have been + * sent or the crash reporter has not been started, null is returned. */ getLastCrashReport(): CrashReport; /** @@ -2628,7 +2419,7 @@ declare namespace Electron { class Debugger extends EventEmitter { - // Docs: http://electronjs.org/docs/api/debugger + // Docs: http://electron.atom.io/docs/api/debugger /** * Emitted when debugging session is terminated. This happens either when @@ -2714,7 +2505,7 @@ declare namespace Electron { interface DesktopCapturer extends EventEmitter { - // Docs: http://electronjs.org/docs/api/desktop-capturer + // Docs: http://electron.atom.io/docs/api/desktop-capturer /** * Starts gathering information about all available desktop media sources, and @@ -2727,7 +2518,7 @@ declare namespace Electron { interface DesktopCapturerSource { - // Docs: http://electronjs.org/docs/api/structures/desktop-capturer-source + // Docs: http://electron.atom.io/docs/api/structures/desktop-capturer-source /** * A unique identifier that will correspond to the id of the matching returned by @@ -2743,8 +2534,8 @@ declare namespace Electron { */ id: string; /** - * A screen source will be named either Entire Screen or Screen , while the name of - * a window source will match the window title. + * A screen source will be named either Entire Screen or Screen , while the + * name of a window source will match the window title. */ name: string; /** @@ -2758,7 +2549,7 @@ declare namespace Electron { interface Dialog extends EventEmitter { - // Docs: http://electronjs.org/docs/api/dialog + // Docs: http://electron.atom.io/docs/api/dialog /** * On macOS, this displays a modal dialog that shows a message and certificate @@ -2819,7 +2610,7 @@ declare namespace Electron { * file selector and a directory selector, so if you set properties to ['openFile', * 'openDirectory'] on these platforms, a directory selector will be shown. */ - showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); + showOpenDialog(browserWindow: BrowserWindow, options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): string[]; /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can @@ -2832,7 +2623,7 @@ declare namespace Electron { * file selector and a directory selector, so if you set properties to ['openFile', * 'openDirectory'] on these platforms, a directory selector will be shown. */ - showOpenDialog(options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): (string[]) | (undefined); + showOpenDialog(options: OpenDialogOptions, callback?: (filePaths: string[], bookmarks: string[]) => void): string[]; /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can @@ -2840,7 +2631,7 @@ declare namespace Electron { * the API call will be asynchronous and the result will be passed via * callback(filename). */ - showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); + showSaveDialog(browserWindow: BrowserWindow, options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): string; /** * The browserWindow argument allows the dialog to attach itself to a parent * window, making it modal. The filters specifies an array of file types that can @@ -2848,12 +2639,12 @@ declare namespace Electron { * the API call will be asynchronous and the result will be passed via * callback(filename). */ - showSaveDialog(options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): (string) | (undefined); + showSaveDialog(options: SaveDialogOptions, callback?: (filename: string, bookmark: string) => void): string; } interface Display { - // Docs: http://electronjs.org/docs/api/structures/display + // Docs: http://electron.atom.io/docs/api/structures/display bounds: Rectangle; /** @@ -2879,7 +2670,7 @@ declare namespace Electron { class DownloadItem extends EventEmitter { - // Docs: http://electronjs.org/docs/api/download-item + // Docs: http://electron.atom.io/docs/api/download-item /** * Emitted when the download is in a terminal state. This includes a completed @@ -2982,7 +2773,7 @@ declare namespace Electron { interface FileFilter { - // Docs: http://electronjs.org/docs/api/structures/file-filter + // Docs: http://electron.atom.io/docs/api/structures/file-filter extensions: string[]; name: string; @@ -2990,7 +2781,7 @@ declare namespace Electron { interface GlobalShortcut extends EventEmitter { - // Docs: http://electronjs.org/docs/api/global-shortcut + // Docs: http://electron.atom.io/docs/api/global-shortcut /** * When the accelerator is already taken by other applications, this call will @@ -3020,65 +2811,65 @@ declare namespace Electron { interface GPUFeatureStatus { - // Docs: http://electronjs.org/docs/api/structures/gpu-feature-status + // Docs: http://electron.atom.io/docs/api/structures/gpu-feature-status /** - * Canvas. + * Canvas */ '2d_canvas': string; /** - * Flash. + * Flash */ flash_3d: string; /** - * Flash Stage3D. + * Flash Stage3D */ flash_stage3d: string; /** - * Flash Stage3D Baseline profile. + * Flash Stage3D Baseline profile */ flash_stage3d_baseline: string; /** - * Compositing. + * Compositing */ gpu_compositing: string; /** - * Multiple Raster Threads. + * Multiple Raster Threads */ multiple_raster_threads: string; /** - * Native GpuMemoryBuffers. + * Native GpuMemoryBuffers */ native_gpu_memory_buffers: string; /** - * Rasterization. + * Rasterization */ rasterization: string; /** - * Video Decode. + * Video Decode */ video_decode: string; /** - * Video Encode. + * Video Encode */ video_encode: string; /** - * VPx Video Decode. + * VPx Video Decode */ vpx_decode: string; /** - * WebGL. + * WebGL */ webgl: string; /** - * WebGL2. + * WebGL2 */ webgl2: string; } interface InAppPurchase extends EventEmitter { - // Docs: http://electronjs.org/docs/api/in-app-purchase + // Docs: http://electron.atom.io/docs/api/in-app-purchase /** * Emitted when one or more transactions have been updated. @@ -3126,7 +2917,7 @@ declare namespace Electron { class IncomingMessage extends EventEmitter { - // Docs: http://electronjs.org/docs/api/incoming-message + // Docs: http://electron.atom.io/docs/api/incoming-message /** * Emitted when a request has been canceled during an ongoing HTTP transaction. @@ -3187,7 +2978,7 @@ declare namespace Electron { interface IOCounters { - // Docs: http://electronjs.org/docs/api/structures/io-counters + // Docs: http://electron.atom.io/docs/api/structures/io-counters /** * Then number of I/O other operations. @@ -3217,7 +3008,7 @@ declare namespace Electron { interface IpcMain extends EventEmitter { - // Docs: http://electronjs.org/docs/api/ipc-main + // Docs: http://electron.atom.io/docs/api/ipc-main /** * Listens to channel, when a new message arrives listener would be called with @@ -3242,7 +3033,7 @@ declare namespace Electron { interface IpcRenderer extends EventEmitter { - // Docs: http://electronjs.org/docs/api/ipc-renderer + // Docs: http://electron.atom.io/docs/api/ipc-renderer /** * Listens to channel, when a new message arrives listener would be called with @@ -3292,7 +3083,7 @@ declare namespace Electron { interface JumpListCategory { - // Docs: http://electronjs.org/docs/api/structures/jump-list-category + // Docs: http://electron.atom.io/docs/api/structures/jump-list-category /** * Array of objects if type is tasks or custom, otherwise it should be omitted. @@ -3310,7 +3101,7 @@ declare namespace Electron { interface JumpListItem { - // Docs: http://electronjs.org/docs/api/structures/jump-list-item + // Docs: http://electron.atom.io/docs/api/structures/jump-list-item /** * The command line arguments when program is executed. Should only be set if type @@ -3357,7 +3148,7 @@ declare namespace Electron { interface MemoryInfo { - // Docs: http://electronjs.org/docs/api/structures/memory-info + // Docs: http://electron.atom.io/docs/api/structures/memory-info /** * The maximum amount of memory that has ever been pinned to actual physical RAM. @@ -3386,7 +3177,7 @@ declare namespace Electron { interface MemoryUsageDetails { - // Docs: http://electronjs.org/docs/api/structures/memory-usage-details + // Docs: http://electron.atom.io/docs/api/structures/memory-usage-details count: number; liveSize: number; @@ -3395,7 +3186,7 @@ declare namespace Electron { class Menu { - // Docs: http://electronjs.org/docs/api/menu + // Docs: http://electron.atom.io/docs/api/menu /** * Emitted when a popup is closed either manually or with menu.closePopup(). @@ -3422,7 +3213,7 @@ declare namespace Electron { * Note: The returned Menu instance doesn't support dynamic addition or removal of * menu items. Instance properties can still be dynamically modified. */ - static getApplicationMenu(): (Menu) | (null); + static getApplicationMenu(): Menu | null; /** * Sends the action to the first responder of application. This is used for * emulating default macOS menu behaviors. Usually you would use the role property @@ -3436,7 +3227,7 @@ declare namespace Electron { * Windows and Linux but has no effect on macOS. Note: This API has to be called * after the ready event of app module. */ - static setApplicationMenu(menu: (Menu) | (null)): void; + static setApplicationMenu(menu: Menu | null): void; /** * Appends the menuItem to the menu. */ @@ -3453,13 +3244,13 @@ declare namespace Electron { /** * Pops up this menu as a context menu in the BrowserWindow. */ - popup(options?: PopupOptions): void; + popup(options: PopupOptions): void; items: MenuItem[]; } class MenuItem { - // Docs: http://electronjs.org/docs/api/menu-item + // Docs: http://electron.atom.io/docs/api/menu-item constructor(options: MenuItemConstructorOptions); checked: boolean; @@ -3471,21 +3262,21 @@ declare namespace Electron { interface MimeTypedBuffer { - // Docs: http://electronjs.org/docs/api/structures/mime-typed-buffer + // Docs: http://electron.atom.io/docs/api/structures/mime-typed-buffer /** - * The actual Buffer content. + * The actual Buffer content */ data: Buffer; /** - * The mimeType of the Buffer that you are sending. + * The mimeType of the Buffer that you are sending */ mimeType: string; } class NativeImage { - // Docs: http://electronjs.org/docs/api/native-image + // Docs: http://electron.atom.io/docs/api/native-image /** * Creates an empty NativeImage instance. @@ -3503,14 +3294,7 @@ declare namespace Electron { * Creates a new NativeImage instance from the NSImage that maps to the given image * name. See NSImageName for a list of possible values. The hslShift is applied to * the image with the following rules This means that [-1, 0, 1] will make the - * image completely white and [-1, 1, 0] will make the image completely black. In - * some cases, the NSImageName doesn't match its string representation; one example - * of this is NSFolderImageName, whose string representation would actually be - * NSFolder. Therefore, you'll need to determine the correct string representation - * for your image before passing it in. This can be done with the following: echo - * -e '#import \nint main() { NSLog(@"%@", SYSTEM_IMAGE_NAME); }' | - * clang -otest -x objective-c -framework Cocoa - && ./test where SYSTEM_IMAGE_NAME - * should be replaced with any value from this list. + * image completely white and [-1, 1, 0] will make the image completely black. */ static createFromNamedImage(imageName: string, hslShift: number[]): NativeImage; /** @@ -3559,7 +3343,7 @@ declare namespace Electron { interface Net extends EventEmitter { - // Docs: http://electronjs.org/docs/api/net + // Docs: http://electron.atom.io/docs/api/net /** * Creates a ClientRequest instance using the provided options which are directly @@ -3567,12 +3351,12 @@ declare namespace Electron { * to issue both secure and insecure HTTP requests according to the specified * protocol scheme in the options object. */ - request(options: (any) | (string)): ClientRequest; + request(options: any | string): ClientRequest; } interface NetLog extends EventEmitter { - // Docs: http://electronjs.org/docs/api/net-log + // Docs: http://electron.atom.io/docs/api/net-log /** * Starts recording network events to path. @@ -3595,7 +3379,7 @@ declare namespace Electron { class Notification extends EventEmitter { - // Docs: http://electronjs.org/docs/api/notification + // Docs: http://electron.atom.io/docs/api/notification on(event: 'action', listener: (event: Event, /** @@ -3685,7 +3469,7 @@ declare namespace Electron { interface NotificationAction { - // Docs: http://electronjs.org/docs/api/structures/notification-action + // Docs: http://electron.atom.io/docs/api/structures/notification-action /** * The label for the given action. @@ -3699,7 +3483,7 @@ declare namespace Electron { interface Point { - // Docs: http://electronjs.org/docs/api/structures/point + // Docs: http://electron.atom.io/docs/api/structures/point x: number; y: number; @@ -3707,7 +3491,7 @@ declare namespace Electron { interface PowerMonitor extends EventEmitter { - // Docs: http://electronjs.org/docs/api/power-monitor + // Docs: http://electron.atom.io/docs/api/power-monitor /** * Emitted when the system is about to lock the screen. @@ -3765,7 +3549,7 @@ declare namespace Electron { interface PowerSaveBlocker extends EventEmitter { - // Docs: http://electronjs.org/docs/api/power-save-blocker + // Docs: http://electron.atom.io/docs/api/power-save-blocker isStarted(id: number): boolean; /** @@ -3787,7 +3571,7 @@ declare namespace Electron { interface PrinterInfo { - // Docs: http://electronjs.org/docs/api/structures/printer-info + // Docs: http://electron.atom.io/docs/api/structures/printer-info description: string; isDefault: boolean; @@ -3797,12 +3581,16 @@ declare namespace Electron { interface ProcessMetric { - // Docs: http://electronjs.org/docs/api/structures/process-metric + // Docs: http://electron.atom.io/docs/api/structures/process-metric /** * CPU usage of the process. */ cpu: CPUUsage; + /** + * Memory information for the process. + */ + memory: MemoryInfo; /** * Process id of the process. */ @@ -3815,7 +3603,7 @@ declare namespace Electron { interface Product { - // Docs: http://electronjs.org/docs/api/structures/product + // Docs: http://electron.atom.io/docs/api/structures/product /** * The total size of the content, in bytes. @@ -3854,7 +3642,7 @@ declare namespace Electron { interface Protocol extends EventEmitter { - // Docs: http://electronjs.org/docs/api/protocol + // Docs: http://electron.atom.io/docs/api/protocol /** * Intercepts scheme protocol and uses handler as the protocol's new handler which @@ -3875,7 +3663,7 @@ declare namespace Electron { * Same as protocol.registerStreamProtocol, except that it replaces an existing * protocol handler. */ - interceptStreamProtocol(scheme: string, handler: (request: InterceptStreamProtocolRequest, callback: (stream?: (NodeJS.ReadableStream) | (StreamProtocolResponse)) => void) => void, completion?: (error: Error) => void): void; + interceptStreamProtocol(scheme: string, handler: (request: InterceptStreamProtocolRequest, callback: (stream?: ReadableStream | StreamProtocolResponse) => void) => void, completion?: (error: Error) => void): void; /** * Intercepts scheme protocol and uses handler as the protocol's new handler which * sends a String as a response. @@ -3892,15 +3680,15 @@ declare namespace Electron { * with either a Buffer object or an object that has the data, mimeType, and * charset properties. Example: */ - registerBufferProtocol(scheme: string, handler: (request: RegisterBufferProtocolRequest, callback: (buffer?: (Buffer) | (MimeTypedBuffer)) => void) => void, completion?: (error: Error) => void): void; + registerBufferProtocol(scheme: string, handler: (request: RegisterBufferProtocolRequest, callback: (buffer?: Buffer | MimeTypedBuffer) => void) => void, completion?: (error: Error) => void): void; /** * Registers a protocol of scheme that will send the file as a response. The * handler will be called with handler(request, callback) when a request is going * to be created with scheme. completion will be called with completion(null) when * scheme is successfully registered or completion(error) when failed. To handle * the request, the callback should be called with either the file's path or an - * object that has a path property, e.g. callback(filePath) or callback({ path: - * filePath }). When callback is called with nothing, a number, or an object that + * object that has a path property, e.g. callback(filePath) or callback({path: + * filePath}). When callback is called with nothing, a number, or an object that * has an error property, the request will fail with the error number you * specified. For the available error numbers you can use, please see the net error * list. By default the scheme is treated like http:, which is parsed differently @@ -3944,7 +3732,7 @@ declare namespace Electron { * that implements the readable stream API (emits data/end/error events). For * example, here's how a file could be returned: */ - registerStreamProtocol(scheme: string, handler: (request: RegisterStreamProtocolRequest, callback: (stream?: (NodeJS.ReadableStream) | (StreamProtocolResponse)) => void) => void, completion?: (error: Error) => void): void; + registerStreamProtocol(scheme: string, handler: (request: RegisterStreamProtocolRequest, callback: (stream?: ReadableStream | StreamProtocolResponse) => void) => void, completion?: (error: Error) => void): void; /** * Registers a protocol of scheme that will send a String as a response. The usage * is the same with registerFileProtocol, except that the callback should be called @@ -3964,29 +3752,29 @@ declare namespace Electron { interface Rectangle { - // Docs: http://electronjs.org/docs/api/structures/rectangle + // Docs: http://electron.atom.io/docs/api/structures/rectangle /** - * The height of the rectangle (must be an integer). + * The height of the rectangle (must be an integer) */ height: number; /** - * The width of the rectangle (must be an integer). + * The width of the rectangle (must be an integer) */ width: number; /** - * The x coordinate of the origin of the rectangle (must be an integer). + * The x coordinate of the origin of the rectangle (must be an integer) */ x: number; /** - * The y coordinate of the origin of the rectangle (must be an integer). + * The y coordinate of the origin of the rectangle (must be an integer) */ y: number; } interface Referrer { - // Docs: http://electronjs.org/docs/api/structures/referrer + // Docs: http://electron.atom.io/docs/api/structures/referrer /** * Can be default, unsafe-url, no-referrer-when-downgrade, no-referrer, origin, @@ -4002,7 +3790,7 @@ declare namespace Electron { interface Remote extends MainInterface { - // Docs: http://electronjs.org/docs/api/remote + // Docs: http://electron.atom.io/docs/api/remote getCurrentWebContents(): WebContents; /** @@ -4025,7 +3813,7 @@ declare namespace Electron { interface RemoveClientCertificate { - // Docs: http://electronjs.org/docs/api/structures/remove-client-certificate + // Docs: http://electron.atom.io/docs/api/structures/remove-client-certificate /** * Origin of the server whose associated client certificate must be removed from @@ -4040,7 +3828,7 @@ declare namespace Electron { interface RemovePassword { - // Docs: http://electronjs.org/docs/api/structures/remove-password + // Docs: http://electron.atom.io/docs/api/structures/remove-password /** * When provided, the authentication info related to the origin will only be @@ -4072,7 +3860,7 @@ declare namespace Electron { interface Screen extends EventEmitter { - // Docs: http://electronjs.org/docs/api/screen + // Docs: http://electron.atom.io/docs/api/screen /** * Emitted when newDisplay has been added. @@ -4123,7 +3911,7 @@ declare namespace Electron { * relative to the display nearest to window. If window is null, scaling will be * performed to the display nearest to rect. */ - dipToScreenRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; + dipToScreenRect(window: BrowserWindow | null, rect: Rectangle): Rectangle; getAllDisplays(): Display[]; /** * The current absolute position of the mouse pointer. @@ -4142,44 +3930,44 @@ declare namespace Electron { * relative to the display nearest to window. If window is null, scaling will be * performed to the display nearest to rect. */ - screenToDipRect(window: (BrowserWindow) | (null), rect: Rectangle): Rectangle; + screenToDipRect(window: BrowserWindow | null, rect: Rectangle): Rectangle; } interface ScrubberItem { - // Docs: http://electronjs.org/docs/api/structures/scrubber-item + // Docs: http://electron.atom.io/docs/api/structures/scrubber-item /** - * The image to appear in this item. + * The image to appear in this item */ icon?: NativeImage; /** - * The text to appear in this item. + * The text to appear in this item */ label?: string; } interface SegmentedControlSegment { - // Docs: http://electronjs.org/docs/api/structures/segmented-control-segment + // Docs: http://electron.atom.io/docs/api/structures/segmented-control-segment /** - * Whether this segment is selectable. Default: true. + * Whether this segment is selectable. Default: true */ enabled?: boolean; /** - * The image to appear in this segment. + * The image to appear in this segment */ icon?: NativeImage; /** - * The text to appear in this segment. + * The text to appear in this segment */ label?: string; } class Session extends EventEmitter { - // Docs: http://electronjs.org/docs/api/session + // Docs: http://electron.atom.io/docs/api/session /** * If partition starts with persist:, the page will use a persistent session @@ -4219,7 +4007,7 @@ declare namespace Electron { /** * Clears the session’s HTTP authentication cache. */ - clearAuthCache(options: (RemovePassword) | (RemoveClientCertificate), callback?: Function): void; + clearAuthCache(options: RemovePassword | RemoveClientCertificate, callback?: Function): void; /** * Clears the session’s HTTP cache. */ @@ -4278,18 +4066,12 @@ declare namespace Electron { * Downloads under the respective app folder. */ setDownloadPath(path: string): void; - /** - * Sets the handler which can be used to respond to permission checks for the - * session. Returning true will allow the permission and false will reject it. To - * clear the handler, call setPermissionCheckHandler(null). - */ - setPermissionCheckHandler(handler: ((webContents: WebContents, permission: string, requestingOrigin: string, details: PermissionCheckHandlerDetails) => boolean) | (null)): void; /** * Sets the handler which can be used to respond to permission requests for the * session. Calling callback(true) will allow the permission and callback(false) * will reject it. To clear the handler, call setPermissionRequestHandler(null). */ - setPermissionRequestHandler(handler: ((webContents: WebContents, permission: string, callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerDetails) => void) | (null)): void; + setPermissionRequestHandler(handler: (webContents: WebContents, permission: string, callback: (permissionGranted: boolean) => void, details: PermissionRequestHandlerDetails) => void | null): void; /** * Adds scripts that will be executed on ALL web contents that are associated with * this session just before normal preload scripts run. @@ -4318,7 +4100,7 @@ declare namespace Electron { interface Shell { - // Docs: http://electronjs.org/docs/api/shell + // Docs: http://electron.atom.io/docs/api/shell /** * Play the beep sound. @@ -4358,7 +4140,7 @@ declare namespace Electron { interface ShortcutDetails { - // Docs: http://electronjs.org/docs/api/structures/shortcut-details + // Docs: http://electron.atom.io/docs/api/structures/shortcut-details /** * The Application User Model ID. Default is empty. @@ -4394,7 +4176,7 @@ declare namespace Electron { interface Size { - // Docs: http://electronjs.org/docs/api/structures/size + // Docs: http://electron.atom.io/docs/api/structures/size height: number; width: number; @@ -4402,25 +4184,25 @@ declare namespace Electron { interface StreamProtocolResponse { - // Docs: http://electronjs.org/docs/api/structures/stream-protocol-response + // Docs: http://electron.atom.io/docs/api/structures/stream-protocol-response /** - * A Node.js readable stream representing the response body. + * A Node.js readable stream representing the response body */ - data: NodeJS.ReadableStream; + data: ReadableStream; /** - * An object containing the response headers. + * An object containing the response headers */ headers: Headers; /** - * The HTTP response code. + * The HTTP response code */ statusCode: number; } interface SystemPreferences extends EventEmitter { - // Docs: http://electronjs.org/docs/api/system-preferences + // Docs: http://electron.atom.io/docs/api/system-preferences on(event: 'accent-color-changed', listener: (event: Event, /** @@ -4442,30 +4224,6 @@ declare namespace Electron { * The new RGBA color the user assigned to be their system accent color. */ newColor: string) => void): this; - /** - * NOTE: This event is only emitted after you have called - * startAppLevelAppearanceTrackingOS - */ - on(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - once(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - addListener(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; - removeListener(event: 'appearance-changed', listener: ( - /** - * Can be `dark` or `light` - */ - newAppearance: ('dark' | 'light')) => void): this; on(event: 'color-changed', listener: (event: Event) => void): this; once(event: 'color-changed', listener: (event: Event) => void): this; addListener(event: 'color-changed', listener: (event: Event) => void): this; @@ -4494,41 +4252,8 @@ declare namespace Electron { * used, `false` otherwise. */ invertedColorScheme: boolean) => void): this; - /** - * Important: In order to properly leverage this API, you must set the - * NSMicrophoneUsageDescription and NSCameraUsageDescription strings in your app's - * Info.plist file. The values for these keys will be used to populate the - * permission dialogs so that the user will be properly informed as to the purpose - * of the permission request. See Electron Application Distribution for more - * information about how to set these in the context of Electron. This user consent - * was not required until macOS 10.14 Mojave, so this method will always return - * true if your system is running 10.13 High Sierra or lower. - */ - askForMediaAccess(mediaType: 'microphone' | 'camera'): Promise; getAccentColor(): string; - /** - * Gets the macOS appearance setting that you have declared you want for your - * application, maps to NSApplication.appearance. You can use the - * setAppLevelAppearance API to set this value. - */ - getAppLevelAppearance(): ('dark' | 'light' | 'unknown'); getColor(color: '3d-dark-shadow' | '3d-face' | '3d-highlight' | '3d-light' | '3d-shadow' | 'active-border' | 'active-caption' | 'active-caption-gradient' | 'app-workspace' | 'button-text' | 'caption-text' | 'desktop' | 'disabled-text' | 'highlight' | 'highlight-text' | 'hotlight' | 'inactive-border' | 'inactive-caption' | 'inactive-caption-gradient' | 'inactive-caption-text' | 'info-background' | 'info-text' | 'menu' | 'menu-highlight' | 'menubar' | 'menu-text' | 'scrollbar' | 'window' | 'window-frame' | 'window-text'): string; - /** - * Gets the macOS appearance setting that is currently applied to your application, - * maps to NSApplication.effectiveAppearance Please note that until Electron is - * built targeting the 10.14 SDK, your application's effectiveAppearance will - * default to 'light' and won't inherit the OS preference. In the interim in order - * for your application to inherit the OS preference you must set the - * NSRequiresAquaSystemAppearance key in your apps Info.plist to false. If you are - * using electron-packager or electron-forge just set the enableDarwinDarkMode - * packager option to true. See the Electron Packager API for more details. - */ - getEffectiveAppearance(): ('dark' | 'light' | 'unknown'); - /** - * This user consent was not required until macOS 10.14 Mojave, so this method will - * always return granted if your system is running 10.13 High Sierra or lower. - */ - getMediaAccessStatus(mediaType: string): ('not-determined' | 'granted' | 'denied' | 'restricted' | 'unknown'); /** * Some popular key and types are: */ @@ -4541,7 +4266,6 @@ declare namespace Electron { isDarkMode(): boolean; isInvertedColorScheme(): boolean; isSwipeTrackingFromScrollEventsEnabled(): boolean; - isTrustedAccessibilityClient(prompt: boolean): boolean; /** * Posts event as native notifications of macOS. The userInfo is an Object that * contains the user information dictionary sent along with the notification. @@ -4566,11 +4290,6 @@ declare namespace Electron { * global value of a key previously set with setUserDefault. */ removeUserDefault(key: string): void; - /** - * Sets the appearance setting for your application, this should override the - * system default and override the value of getEffectiveAppearance. - */ - setAppLevelAppearance(appearance: 'dark' | 'light'): void; /** * Set the value of key in NSUserDefaults. Note that type should match actual type * of value. An exception is thrown if they don't. Some popular key and types are: @@ -4614,7 +4333,7 @@ declare namespace Electron { interface Task { - // Docs: http://electronjs.org/docs/api/structures/task + // Docs: http://electron.atom.io/docs/api/structures/task /** * The command line arguments when program is executed. @@ -4649,7 +4368,7 @@ declare namespace Electron { interface ThumbarButton { - // Docs: http://electronjs.org/docs/api/structures/thumbar-button + // Docs: http://electron.atom.io/docs/api/structures/thumbar-button click: Function; /** @@ -4669,7 +4388,7 @@ declare namespace Electron { class TouchBarButton extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-button + // Docs: http://electron.atom.io/docs/api/touch-bar-button constructor(options: TouchBarButtonConstructorOptions); backgroundColor: string; @@ -4679,7 +4398,7 @@ declare namespace Electron { class TouchBarColorPicker extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-color-picker + // Docs: http://electron.atom.io/docs/api/touch-bar-color-picker constructor(options: TouchBarColorPickerConstructorOptions); availableColors: string[]; @@ -4688,14 +4407,14 @@ declare namespace Electron { class TouchBarGroup extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-group + // Docs: http://electron.atom.io/docs/api/touch-bar-group constructor(options: TouchBarGroupConstructorOptions); } class TouchBarLabel extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-label + // Docs: http://electron.atom.io/docs/api/touch-bar-label constructor(options: TouchBarLabelConstructorOptions); label: string; @@ -4704,7 +4423,7 @@ declare namespace Electron { class TouchBarPopover extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-popover + // Docs: http://electron.atom.io/docs/api/touch-bar-popover constructor(options: TouchBarPopoverConstructorOptions); icon: NativeImage; @@ -4713,7 +4432,7 @@ declare namespace Electron { class TouchBarScrubber extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-scrubber + // Docs: http://electron.atom.io/docs/api/touch-bar-scrubber constructor(options: TouchBarScrubberConstructorOptions); continuous: boolean; @@ -4726,7 +4445,7 @@ declare namespace Electron { class TouchBarSegmentedControl extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-segmented-control + // Docs: http://electron.atom.io/docs/api/touch-bar-segmented-control constructor(options: TouchBarSegmentedControlConstructorOptions); segments: SegmentedControlSegment[]; @@ -4736,7 +4455,7 @@ declare namespace Electron { class TouchBarSlider extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-slider + // Docs: http://electron.atom.io/docs/api/touch-bar-slider constructor(options: TouchBarSliderConstructorOptions); label: string; @@ -4747,14 +4466,14 @@ declare namespace Electron { class TouchBarSpacer extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar-spacer + // Docs: http://electron.atom.io/docs/api/touch-bar-spacer constructor(options: TouchBarSpacerConstructorOptions); } class TouchBar extends EventEmitter { - // Docs: http://electronjs.org/docs/api/touch-bar + // Docs: http://electron.atom.io/docs/api/touch-bar constructor(options: TouchBarConstructorOptions); escapeItem: (TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null); @@ -4771,7 +4490,7 @@ declare namespace Electron { interface TraceCategoriesAndOptions { - // Docs: http://electronjs.org/docs/api/structures/trace-categories-and-options + // Docs: http://electron.atom.io/docs/api/structures/trace-categories-and-options /** * – is a filter to control what category groups should be traced. A filter can @@ -4798,7 +4517,7 @@ declare namespace Electron { interface TraceConfig { - // Docs: http://electronjs.org/docs/api/structures/trace-config + // Docs: http://electron.atom.io/docs/api/structures/trace-config excluded_categories?: string[]; included_categories?: string[]; @@ -4807,7 +4526,7 @@ declare namespace Electron { interface Transaction { - // Docs: http://electronjs.org/docs/api/structures/transaction + // Docs: http://electron.atom.io/docs/api/structures/transaction /** * The error code if an error occurred while processing the transaction. @@ -4839,7 +4558,7 @@ declare namespace Electron { class Tray extends EventEmitter { - // Docs: http://electronjs.org/docs/api/tray + // Docs: http://electron.atom.io/docs/api/tray /** * Emitted when the tray balloon is clicked. @@ -5091,7 +4810,7 @@ declare namespace Electron { * The bounds of tray icon. */ bounds: Rectangle) => void): this; - constructor(image: (NativeImage) | (string)); + constructor(image: NativeImage | string); /** * Destroys the tray icon immediately. */ @@ -5115,7 +4834,7 @@ declare namespace Electron { /** * Sets the context menu for this icon. */ - setContextMenu(menu: (Menu) | (null)): void; + setContextMenu(menu: Menu | null): void; /** * Sets when the tray's icon background becomes highlighted (in blue). Note: You * can use highlightMode with a BrowserWindow by toggling between 'never' and @@ -5131,11 +4850,11 @@ declare namespace Electron { /** * Sets the image associated with this tray icon. */ - setImage(image: (NativeImage) | (string)): void; + setImage(image: NativeImage | string): void; /** * Sets the image associated with this tray icon when pressed on macOS. */ - setPressedImage(image: (NativeImage) | (string)): void; + setPressedImage(image: NativeImage | string): void; /** * Sets the title displayed aside of the tray icon in the status bar (Support ANSI * colors). @@ -5149,7 +4868,7 @@ declare namespace Electron { interface UploadBlob { - // Docs: http://electronjs.org/docs/api/structures/upload-blob + // Docs: http://electron.atom.io/docs/api/structures/upload-blob /** * UUID of blob data to upload. @@ -5163,7 +4882,7 @@ declare namespace Electron { interface UploadData { - // Docs: http://electronjs.org/docs/api/structures/upload-data + // Docs: http://electron.atom.io/docs/api/structures/upload-data /** * UUID of blob data. Use method to retrieve the data. @@ -5181,7 +4900,7 @@ declare namespace Electron { interface UploadFile { - // Docs: http://electronjs.org/docs/api/structures/upload-file + // Docs: http://electron.atom.io/docs/api/structures/upload-file /** * Path of file to be uploaded. @@ -5207,7 +4926,7 @@ declare namespace Electron { interface UploadRawData { - // Docs: http://electronjs.org/docs/api/structures/upload-raw-data + // Docs: http://electron.atom.io/docs/api/structures/upload-raw-data /** * Data to be uploaded. @@ -5221,7 +4940,7 @@ declare namespace Electron { class WebContents extends EventEmitter { - // Docs: http://electronjs.org/docs/api/web-contents + // Docs: http://electron.atom.io/docs/api/web-contents static fromId(id: number): WebContents; static getAllWebContents(): WebContents[]; @@ -5445,22 +5164,22 @@ declare namespace Electron { */ on(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ` + * The guest web contents that is used by the ``. */ webContents: WebContents) => void): this; once(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ` + * The guest web contents that is used by the ``. */ webContents: WebContents) => void): this; addListener(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ` + * The guest web contents that is used by the ``. */ webContents: WebContents) => void): this; removeListener(event: 'did-attach-webview', listener: (event: Event, /** - * The guest web contents that is used by the ` + * The guest web contents that is used by the ``. */ webContents: WebContents) => void): this; /** @@ -5471,22 +5190,22 @@ declare namespace Electron { /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: (string) | (null)) => void): this; + color: string | null) => void): this; once(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: (string) | (null)) => void): this; + color: string | null) => void): this; addListener(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: (string) | (null)) => void): this; + color: string | null) => void): this; removeListener(event: 'did-change-theme-color', listener: (event: Event, /** * Theme color is in format of '#rrggbb'. It is `null` when no theme color is set. */ - color: (string) | (null)) => void): this; + color: string | null) => void): this; /** * This event is like did-finish-load but emitted when the load failed or was * cancelled, e.g. window.stop() is invoked. The full list of error codes and their @@ -5675,35 +5394,6 @@ declare namespace Electron { isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - /** - * Emitted after a server side redirect occurs during navigation. For example a - * 302 redirect. This event can not be prevented, if you want to prevent redirects - * you should checkout out the will-redirect event above. - */ - on(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'did-redirect-navigation', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; /** * Corresponds to the points in time when the spinner of the tab started spinning. */ @@ -5715,26 +5405,22 @@ declare namespace Electron { * Emitted when any frame (including main) starts navigating. isInplace will be * true for in-page navigations. */ - on(event: 'did-start-navigation', listener: (event: Event, - url: string, + on(event: 'did-start-navigation', listener: (url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - once(event: 'did-start-navigation', listener: (event: Event, - url: string, + once(event: 'did-start-navigation', listener: (url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - addListener(event: 'did-start-navigation', listener: (event: Event, - url: string, + addListener(event: 'did-start-navigation', listener: (url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, frameRoutingId: number) => void): this; - removeListener(event: 'did-start-navigation', listener: (event: Event, - url: string, + removeListener(event: 'did-start-navigation', listener: (url: string, isInPlace: boolean, isMainFrame: boolean, frameProcessId: number, @@ -5962,76 +5648,6 @@ declare namespace Electron { removeListener(event: 'plugin-crashed', listener: (event: Event, name: string, version: string) => void): this; - /** - * Emitted when remote.getBuiltin() is called in the renderer process. Calling - * event.preventDefault() will prevent the module from being returned. Custom value - * can be returned by setting event.returnValue. - */ - on(event: 'remote-get-builtin', listener: (event: Event, - moduleName: string) => void): this; - once(event: 'remote-get-builtin', listener: (event: Event, - moduleName: string) => void): this; - addListener(event: 'remote-get-builtin', listener: (event: Event, - moduleName: string) => void): this; - removeListener(event: 'remote-get-builtin', listener: (event: Event, - moduleName: string) => void): this; - /** - * Emitted when remote.getCurrentWebContents() is called in the renderer process. - * Calling event.preventDefault() will prevent the object from being returned. - * Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; - once(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; - addListener(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; - removeListener(event: 'remote-get-current-web-contents', listener: (event: Event) => void): this; - /** - * Emitted when remote.getCurrentWindow() is called in the renderer process. - * Calling event.preventDefault() will prevent the object from being returned. - * Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-current-window', listener: (event: Event) => void): this; - once(event: 'remote-get-current-window', listener: (event: Event) => void): this; - addListener(event: 'remote-get-current-window', listener: (event: Event) => void): this; - removeListener(event: 'remote-get-current-window', listener: (event: Event) => void): this; - /** - * Emitted when remote.getGlobal() is called in the renderer process. Calling - * event.preventDefault() will prevent the global from being returned. Custom value - * can be returned by setting event.returnValue. - */ - on(event: 'remote-get-global', listener: (event: Event, - globalName: string) => void): this; - once(event: 'remote-get-global', listener: (event: Event, - globalName: string) => void): this; - addListener(event: 'remote-get-global', listener: (event: Event, - globalName: string) => void): this; - removeListener(event: 'remote-get-global', listener: (event: Event, - globalName: string) => void): this; - /** - * Emitted when .getWebContents() is called in the renderer process. - * Calling event.preventDefault() will prevent the object from being returned. - * Custom value can be returned by setting event.returnValue. - */ - on(event: 'remote-get-guest-web-contents', listener: (event: Event, - guestWebContents: WebContents) => void): this; - once(event: 'remote-get-guest-web-contents', listener: (event: Event, - guestWebContents: WebContents) => void): this; - addListener(event: 'remote-get-guest-web-contents', listener: (event: Event, - guestWebContents: WebContents) => void): this; - removeListener(event: 'remote-get-guest-web-contents', listener: (event: Event, - guestWebContents: WebContents) => void): this; - /** - * Emitted when remote.require() is called in the renderer process. Calling - * event.preventDefault() will prevent the module from being returned. Custom value - * can be returned by setting event.returnValue. - */ - on(event: 'remote-require', listener: (event: Event, - moduleName: string) => void): this; - once(event: 'remote-require', listener: (event: Event, - moduleName: string) => void): this; - addListener(event: 'remote-require', listener: (event: Event, - moduleName: string) => void): this; - removeListener(event: 'remote-require', listener: (event: Event, - moduleName: string) => void): this; /** * Emitted when the unresponsive web page becomes responsive again. */ @@ -6111,7 +5727,8 @@ declare namespace Electron { */ webPreferences: any, /** - * The other ` + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. */ params: any) => void): this; once(event: 'will-attach-webview', listener: (event: Event, @@ -6121,7 +5738,8 @@ declare namespace Electron { */ webPreferences: any, /** - * The other ` + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. */ params: any) => void): this; addListener(event: 'will-attach-webview', listener: (event: Event, @@ -6131,7 +5749,8 @@ declare namespace Electron { */ webPreferences: any, /** - * The other ` + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. */ params: any) => void): this; removeListener(event: 'will-attach-webview', listener: (event: Event, @@ -6141,7 +5760,8 @@ declare namespace Electron { */ webPreferences: any, /** - * The other ` + * The other `` parameters such as the `src` URL. This object can be + * modified to adjust the parameters of the guest page. */ params: any) => void): this; /** @@ -6170,36 +5790,6 @@ declare namespace Electron { once(event: 'will-prevent-unload', listener: (event: Event) => void): this; addListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; removeListener(event: 'will-prevent-unload', listener: (event: Event) => void): this; - /** - * Emitted as a server side redirect occurs during navigation. For example a 302 - * redirect. This event will be emitted after did-start-navigation and always - * before the did-redirect-navigation event for the same navigation. Calling - * event.preventDefault() will prevent the navigation (not just the redirect). - */ - on(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - once(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - addListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; - removeListener(event: 'will-redirect', listener: (event: Event, - url: string, - isInPlace: boolean, - isMainFrame: boolean, - frameProcessId: number, - frameRoutingId: number) => void): this; /** * Adds the specified path to DevTools workspace. Must be used after DevTools * creation: @@ -6305,7 +5895,6 @@ declare namespace Electron { getPrinters(): PrinterInfo[]; getProcessId(): number; getTitle(): string; - getType(): ('backgroundPage' | 'window' | 'browserView' | 'remote' | 'webview' | 'offscreen'); getURL(): string; getUserAgent(): string; getWebRTCIPHandlingPolicy(): string; @@ -6364,7 +5953,6 @@ declare namespace Electron { invalidate(): void; isAudioMuted(): boolean; isCrashed(): boolean; - isCurrentlyAudible(): boolean; isDestroyed(): boolean; isDevToolsFocused(): boolean; isDevToolsOpened(): boolean; @@ -6379,7 +5967,7 @@ declare namespace Electron { * relative to the root of your application. For instance an app structure like * this: Would require code like this */ - loadFile(filePath: string, options?: LoadFileOptions): void; + loadFile(filePath: string): void; /** * Loads the url in the window. The url must contain the protocol prefix, e.g. the * http:// or file://. If the load should bypass http cache then use the pragma @@ -6404,8 +5992,8 @@ declare namespace Electron { * Prints window's web page. When silent is set to true, Electron will pick the * system's default printer if deviceName is empty and the default settings for * printing. Calling window.print() in web page is equivalent to calling - * webContents.print({ silent: false, printBackground: false, deviceName: '' }). - * Use page-break-before: always; CSS style to force to print to a new page. + * webContents.print({silent: false, printBackground: false, deviceName: ''}). Use + * page-break-before: always; CSS style to force to print to a new page. */ print(options?: PrintOptions, callback?: (success: boolean) => void): void; /** @@ -6466,11 +6054,6 @@ declare namespace Electron { * Mute the audio on the current web page. */ setAudioMuted(muted: boolean): void; - /** - * Controls whether or not this WebContents will throttle animations and timers - * when the page becomes backgrounded. This also affects the Page Visibility API. - */ - setBackgroundThrottling(allowed: boolean): void; /** * Uses the devToolsWebContents as the target WebContents to show devtools. The * devToolsWebContents must not have done any navigation, and it should not be used @@ -6548,10 +6131,6 @@ declare namespace Electron { * If offscreen rendering is enabled and painting, stop painting. */ stopPainting(): void; - /** - * Takes a V8 heap snapshot and saves it to filePath. - */ - takeHeapSnapshot(filePath: string): Promise; /** * Toggles the developer tools. */ @@ -6579,7 +6158,7 @@ declare namespace Electron { interface WebFrame extends EventEmitter { - // Docs: http://electronjs.org/docs/api/web-frame + // Docs: http://electron.atom.io/docs/api/web-frame /** * Attempts to free memory that is no longer being used (like images from a @@ -6597,7 +6176,7 @@ declare namespace Electron { */ executeJavaScript(code: string, userGesture?: boolean, callback?: (result: any) => void): Promise; /** - * Work like executeJavaScript but evaluates scripts in an isolated context. + * Work like executeJavaScript but evaluates scripts in isolated context. */ executeJavaScriptInIsolatedWorld(worldId: number, scripts: WebSource[], userGesture?: boolean, callback?: (result: any) => void): void; findFrameByName(name: string): WebFrame; @@ -6700,7 +6279,7 @@ declare namespace Electron { class WebRequest extends EventEmitter { - // Docs: http://electronjs.org/docs/api/web-request + // Docs: http://electron.atom.io/docs/api/web-request /** * The listener will be called with listener(details) when a server initiated @@ -6794,7 +6373,7 @@ declare namespace Electron { interface WebSource { - // Docs: http://electronjs.org/docs/api/structures/web-source + // Docs: http://electron.atom.io/docs/api/structures/web-source code: string; /** @@ -6806,7 +6385,7 @@ declare namespace Electron { interface WebviewTag extends HTMLElement { - // Docs: http://electronjs.org/docs/api/webview-tag + // Docs: http://electron.atom.io/docs/api/webview-tag /** * Fired when a load has committed. This includes navigation within the current @@ -6930,6 +6509,11 @@ declare namespace Electron { */ addEventListener(event: 'crashed', listener: (event: Event) => void, useCapture?: boolean): this; removeEventListener(event: 'crashed', listener: (event: Event) => void): this; + /** + * Fired when the gpu process is crashed. + */ + addEventListener(event: 'gpu-crashed', listener: (event: Event) => void, useCapture?: boolean): this; + removeEventListener(event: 'gpu-crashed', listener: (event: Event) => void): this; /** * Fired when a plugin process is crashed. */ @@ -7013,10 +6597,6 @@ declare namespace Electron { * Executes editing command delete in page. */ delete(): void; - /** - * Initiates a download of the resource at url without navigating. - */ - downloadURL(url: string): void; /** * Evaluates code in page. If userGesture is set, it will create the user gesture * context in the page. HTML APIs like requestFullScreen, which require user @@ -7031,21 +6611,7 @@ declare namespace Electron { getTitle(): string; getURL(): string; getUserAgent(): string; - /** - * It depends on the remote module, it is therefore not available when this module - * is disabled. - */ getWebContents(): WebContents; - /** - * Sends a request to get current zoom factor, the callback will be called with - * callback(zoomFactor). - */ - getZoomFactor(callback: (zoomFactor: number) => void): void; - /** - * Sends a request to get current zoom level, the callback will be called with - * callback(zoomLevel). - */ - getZoomLevel(callback: (zoomLevel: number) => void): void; /** * Makes the guest page go back. */ @@ -7080,11 +6646,9 @@ declare namespace Electron { inspectServiceWorker(): void; isAudioMuted(): boolean; isCrashed(): boolean; - isCurrentlyAudible(): boolean; isDevToolsFocused(): boolean; isDevToolsOpened(): boolean; isLoading(): boolean; - isLoadingMainFrame(): boolean; isWaitingForResponse(): boolean; /** * Loads the url in the webview, the url must contain the protocol prefix, e.g. the @@ -7152,18 +6716,10 @@ declare namespace Electron { * Set guest page muted. */ setAudioMuted(muted: boolean): void; - /** - * Sets the maximum and minimum layout-based (i.e. non-visual) zoom level. - */ - setLayoutZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; /** * Overrides the user agent for the guest page. */ setUserAgent(userAgent: string): void; - /** - * Sets the maximum and minimum pinch-to-zoom level. - */ - setVisualZoomLevelLimits(minimumLevel: number, maximumLevel: number): void; /** * Changes the zoom factor to the specified factor. Zoom factor is zoom percent * divided by 100, so 300% = 3.0. @@ -7172,8 +6728,7 @@ declare namespace Electron { /** * Changes the zoom level to the specified level. The original size is 0 and each * increment above or below represents zooming 20% larger or smaller to default - * limits of 300% and 50% of original size, respectively. The formula for this is - * scale := 1.2 ^ level. + * limits of 300% and 50% of original size, respectively. */ setZoomLevel(level: number): void; /** @@ -7226,11 +6781,6 @@ declare namespace Electron { * RuntimeEnabledFeatures.json5 file. */ enableblinkfeatures?: string; - /** - * When this attribute is false the guest page in webview will not have access to - * the remote module. The remote module is avaiable by default. - */ - enableremotemodule?: string; /** * Sets the referrer URL for the guest page. */ @@ -7504,7 +7054,7 @@ declare namespace Electron { * visual effects, you can also leave it undefined so the executable's icon will be * used. */ - icon?: (NativeImage) | (string); + icon?: NativeImage | string; /** * Whether window should be shown when created. Default is true. */ @@ -7541,8 +7091,9 @@ declare namespace Electron { enableLargerThanScreen?: boolean; /** * Window's background color as a hexadecimal value, like #66CD00 or #FFF or - * #80FFFFFF (alpha is supported if transparent is set to true). Default is #FFF - * (white). + * #80FFFFFF (alpha is supported). Default is #FFF (white). If transparent is set + * to true, only values with transparent (#00-------) or opaque (#FF-----) alpha + * values are respected. */ backgroundColor?: string; /** @@ -7769,7 +7320,7 @@ declare namespace Electron { } interface CrashReporterStartOptions { - companyName: string; + companyName?: string; /** * URL that crash reports will be sent to as POST. */ @@ -7871,8 +7422,7 @@ declare namespace Electron { */ value?: string; /** - * The domain of the cookie; this will be normalized with a preceding dot so that - * it's also valid for subdomains. Empty by default if omitted. + * The domain of the cookie. Empty by default if omitted. */ domain?: string; /** @@ -7926,7 +7476,7 @@ declare namespace Electron { /** * - */ - icon?: (NativeImage) | (string); + icon?: NativeImage | string; title: string; content: string; } @@ -7968,7 +7518,7 @@ declare namespace Electron { /** * Sets the image associated with this dock icon. */ - setIcon: (image: (NativeImage) | (string)) => void; + setIcon: (image: NativeImage | string) => void; } interface EnableNetworkEmulationOptions { @@ -8166,7 +7716,6 @@ declare namespace Electron { interface InterceptHttpProtocolRequest { url: string; - headers: Headers; referrer: string; method: string; uploadData: UploadData[]; @@ -8223,26 +7772,11 @@ declare namespace Electron { isMainFrame: boolean; } - interface LoadFileOptions { - /** - * Passed to url.format(). - */ - query?: Query; - /** - * Passed to url.format(). - */ - search?: string; - /** - * Passed to url.format(). - */ - hash?: string; - } - interface LoadURLOptions { /** * An HTTP Referrer url. */ - httpReferrer?: (string) | (Referrer); + httpReferrer?: string | Referrer; /** * A user agent originating the request. */ @@ -8251,7 +7785,7 @@ declare namespace Electron { * Extra headers separated by "\n" */ extraHeaders?: string; - postData?: (UploadRawData[]) | (UploadFile[]) | (UploadBlob[]); + postData?: UploadRawData[] | UploadFile[] | UploadBlob[]; /** * Base url (with trailing path separator) for files to be loaded by the data url. * This is needed only if the specified url is a data url and needs to load other @@ -8322,7 +7856,7 @@ declare namespace Electron { label?: string; sublabel?: string; accelerator?: Accelerator; - icon?: (NativeImage) | (string); + icon?: NativeImage | string; /** * If false, the menu item will be greyed out and unclickable. */ @@ -8345,36 +7879,17 @@ declare namespace Electron { * type: 'submenu' can be omitted. If the value is not a then it will be * automatically converted to one using Menu.buildFromTemplate. */ - submenu?: (MenuItemConstructorOptions[]) | (Menu); + submenu?: MenuItemConstructorOptions[] | Menu; /** * Unique within a single menu. If defined then it can be used as a reference to * this item by the position attribute. */ id?: string; /** - * Inserts this item before the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. Also - * implies that the menu item in question should be placed in the same “group” as - * the item. + * This field allows fine-grained definition of the specific location within a + * given menu. */ - before?: string[]; - /** - * Inserts this item after the item with the specified label. If the referenced - * item doesn't exist the item will be inserted at the end of the menu. - */ - after?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group before the containing group of the item with the specified - * label. - */ - beforeGroupContaining?: string[]; - /** - * Provides a means for a single context menu to declare the placement of their - * containing group after the containing group of the item with the specified - * label. - */ - afterGroupContaining?: string[]; + position?: string; } interface MessageBoxOptions { @@ -8420,7 +7935,7 @@ declare namespace Electron { * The index of the button to be used to cancel the dialog, via the Esc key. By * default this is assigned to the first button with "cancel" or "no" as the label. * If no such labeled buttons exist and this option is not set, 0 will be used as - * the return value or callback response. + * the return value or callback response. This option is ignored on Windows. */ cancelId?: number; /** @@ -8478,7 +7993,7 @@ declare namespace Electron { /** * An icon to use in the notification. */ - icon?: (string) | (NativeImage); + icon?: string | NativeImage; /** * Whether or not to add an inline reply option to the notification. */ @@ -8578,7 +8093,6 @@ declare namespace Electron { method: string; webContentsId?: number; resourceType: string; - referrer: string; timestamp: number; responseHeaders: ResponseHeaders; fromCache: boolean; @@ -8637,7 +8151,7 @@ declare namespace Electron { } interface OnHeadersReceivedResponse { - cancel?: boolean; + cancel: boolean; /** * When provided, the server is assumed to have responded with these headers. */ @@ -8728,11 +8242,7 @@ declare namespace Electron { /** * true to bring the opened application to the foreground. The default is true. */ - activate?: boolean; - /** - * The working directory. - */ - workingDirectory?: string; + activate: boolean; } interface PageFaviconUpdatedEvent extends Event { @@ -8757,8 +8267,8 @@ declare namespace Electron { */ screenSize: Size; /** - * Position the view on the screen (screenPosition == mobile) (default: { x: 0, y: - * 0 }). + * Position the view on the screen (screenPosition == mobile) (default: {x: 0, y: + * 0}). */ viewPosition: Point; /** @@ -8788,26 +8298,11 @@ declare namespace Electron { quantity: number; } - interface PermissionCheckHandlerDetails { - /** - * The security orign of the media check. - */ - securityOrigin: string; - /** - * The type of media access being requested, can be video, audio or unknown - */ - mediaType: ('video' | 'audio' | 'unknown'); - } - interface PermissionRequestHandlerDetails { /** * The url of the openExternal request. */ externalURL: string; - /** - * The types of media access being requested, elements can be video or audio - */ - mediaTypes: Array<'video' | 'audio'>; } interface PluginCrashedEvent extends Event { @@ -8864,7 +8359,7 @@ declare namespace Electron { * Specify page size of the generated PDF. Can be A3, A4, A5, Legal, Letter, * Tabloid or an Object containing height and width in microns. */ - pageSize?: (string) | (Size); + pageSize?: string | Size; /** * Whether to print CSS backgrounds. */ @@ -8881,19 +8376,23 @@ declare namespace Electron { interface ProcessMemoryInfo { /** - * and The amount of memory currently pinned to actual physical RAM in Kilobytes. + * The amount of memory currently pinned to actual physical RAM. */ - residentSet: number; + workingSetSize: number; + /** + * The maximum amount of memory that has ever been pinned to actual physical RAM. + */ + peakWorkingSetSize: number; /** * The amount of memory not shared by other processes, such as JS heap or HTML - * content in Kilobytes. + * content. */ - private: number; + privateBytes: number; /** * The amount of memory shared between processes, typically memory consumed by the - * Electron code itself in Kilobytes. + * Electron code itself. */ - shared: number; + sharedBytes: number; } interface ProgressBarOptions { @@ -8938,7 +8437,6 @@ declare namespace Electron { interface RegisterHttpProtocolRequest { url: string; - headers: Headers; referrer: string; method: string; uploadData: UploadData[]; @@ -9206,8 +8704,8 @@ declare namespace Electron { } interface TouchBarConstructorOptions { - items: Array<(TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer)>; - escapeItem?: (TouchBarButton) | (TouchBarColorPicker) | (TouchBarGroup) | (TouchBarLabel) | (TouchBarPopover) | (TouchBarScrubber) | (TouchBarSegmentedControl) | (TouchBarSlider) | (TouchBarSpacer) | (null); + items: Array; + escapeItem?: TouchBarButton | TouchBarColorPicker | TouchBarGroup | TouchBarLabel | TouchBarPopover | TouchBarScrubber | TouchBarSegmentedControl | TouchBarSlider | TouchBarSpacer | null; } interface TouchBarGroupConstructorOptions { @@ -9373,13 +8871,6 @@ declare namespace Electron { electron?: string; } - interface VisibleOnAllWorkspacesOptions { - /** - * Sets whether the window should be visible above fullscreen windows - */ - visibleOnFullScreen?: boolean; - } - interface WillNavigateEvent extends Event { url: string; } @@ -9473,9 +8964,6 @@ declare namespace Electron { interface Options { } - interface Query { - } - interface RequestHeaders { } @@ -9516,10 +9004,6 @@ declare namespace Electron { * currently experimental and may change or be removed in future Electron releases. */ sandbox?: boolean; - /** - * Whether to enable the module. Default is true. - */ - enableRemoteModule?: boolean; /** * Sets the session used by the page. Instead of passing the Session object * directly, you can also choose to use the partition option instead, which accepts @@ -9588,6 +9072,10 @@ declare namespace Electron { * Enables Chromium's experimental features. Default is false. */ // experimentalFeatures?: boolean; ### VSCODE CHANGE (https://github.com/electron/electron/blob/master/docs/tutorial/security.md) ### + /** + * Enables Chromium's experimental canvas features. Default is false. + */ + experimentalCanvasFeatures?: boolean; /** * Enables scroll bounce (rubber banding) effect on macOS. Default is false. */ @@ -9643,7 +9131,8 @@ declare namespace Electron { * content to ensure the loaded content cannot tamper with the preload script and * any Electron APIs being used. This option uses the same technique used by . You * can access this context in the dev tools by selecting the 'Electron Isolated - * Context' entry in the combo box at the top of the Console tab. + * Context' entry in the combo box at the top of the Console tab. This option is + * currently experimental and may change or be removed in future Electron releases. */ contextIsolation?: boolean; /** @@ -9655,11 +9144,11 @@ declare namespace Electron { nativeWindowOpen?: boolean; /** * Whether to enable the . Defaults to the value of the nodeIntegration option. The - * preload script configured for the will have node integration enabled when it is - * executed so you should ensure remote/untrusted content is not able to create a - * tag with a possibly malicious preload script. You can use the + * preload script configured for the will have node integration enabled + * when it is executed so you should ensure remote/untrusted content is not able to + * create a tag with a possibly malicious preload script. You can use the * will-attach-webview event on to strip away the preload script and to validate or - * alter the 's initial settings. + * alter the 's initial settings. */ webviewTag?: boolean; /** @@ -9741,7 +9230,7 @@ interface Document { declare namespace NodeJS { interface Process extends EventEmitter { - // Docs: http://electronjs.org/docs/api/process + // Docs: http://electron.atom.io/docs/api/process // ### BEGIN VSCODE MODIFICATION ### // /** @@ -9761,12 +9250,6 @@ declare namespace NodeJS { */ crash(): void; getCPUUsage(): Electron.CPUUsage; - /** - * Indicates the creation time of the application. The time is represented as - * number of milliseconds since epoch. It returns null if it is unable to get the - * process creation time. - */ - getCreationTime(): (number) | (null); /** * Returns an object with V8 heap statistics. Note that all statistics are reported * in Kilobytes. @@ -9775,12 +9258,7 @@ declare namespace NodeJS { getIOCounters(): Electron.IOCounters; /** * Returns an object giving memory usage statistics about the current process. Note - * that all statistics are reported in Kilobytes. This api should be called after - * app ready. Chromium does not provide residentSet value for macOS. This is - * because macOS performs in-memory compression of pages that haven't been recently - * used. As a result the resident set size value is not what one would expect. - * private memory is more representative of the actual pre-compression memory usage - * of the process on macOS. + * that all statistics are reported in Kilobytes. */ getProcessMemoryInfo(): Electron.ProcessMemoryInfo; /** @@ -9797,10 +9275,6 @@ declare namespace NodeJS { * whichever is lower for the current process. */ setFdLimit(maxDescriptors: number): void; - /** - * Takes a V8 heap snapshot and saves it to filePath. - */ - takeHeapSnapshot(filePath: string): boolean; /** * A Boolean. When app is started by being passed as parameter to the default app, * this property is true in the main process, otherwise it is undefined. @@ -9826,11 +9300,6 @@ declare namespace NodeJS { * A String representing the path to the resources directory. */ resourcesPath?: string; - /** - * A Boolean. When the renderer process is sandboxed, this property is true, - * otherwise it is undefined. - */ - sandboxed?: boolean; /** * A Boolean that controls whether or not deprecation warnings will be thrown as * exceptions. Setting this to true will throw errors for deprecations. This @@ -9866,4 +9335,4 @@ declare namespace NodeJS { electron: string; chrome: string; } -} \ No newline at end of file +} diff --git a/src/typings/onigasm-umd.d.ts b/src/typings/onigasm-umd.d.ts deleted file mode 100644 index 24396aafa9..0000000000 --- a/src/typings/onigasm-umd.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -declare module "onigasm-umd" { - - function loadWASM(data: string | ArrayBuffer): Promise; - - class OnigString { - constructor(content: string); - readonly content: string; - readonly dispose?: () => void; - } - - class OnigScanner { - constructor(patterns: string[]); - findNextMatchSync(string: string | OnigString, startPosition: number): IOnigMatch; - } - - export interface IOnigCaptureIndex { - index: number - start: number - end: number - length: number - } - - export interface IOnigMatch { - index: number - captureIndices: IOnigCaptureIndex[] - scanner: OnigScanner - } -} \ No newline at end of file diff --git a/src/typings/require.d.ts b/src/typings/require.d.ts index 5b98dc2f4b..76916d8513 100644 --- a/src/typings/require.d.ts +++ b/src/typings/require.d.ts @@ -17,12 +17,7 @@ declare const enum LoaderEventType { NodeEndEvaluatingScript = 32, NodeBeginNativeRequire = 33, - NodeEndNativeRequire = 34, - - CachedDataFound = 60, - CachedDataMissed = 61, - CachedDataRejected = 62, - CachedDataCreated = 63, + NodeEndNativeRequire = 34 } declare class LoaderEvent { diff --git a/src/typings/xterm.d.ts b/src/typings/vscode-xterm.d.ts similarity index 91% rename from src/typings/xterm.d.ts rename to src/typings/vscode-xterm.d.ts index 486f1d42c0..01e47b16b2 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/vscode-xterm.d.ts @@ -9,7 +9,7 @@ /// -declare module 'xterm' { +declare module 'vscode-xterm' { /** * A string representing text font weight. */ @@ -76,6 +76,31 @@ declare module 'xterm' { */ drawBoldTextInBrightColors?: boolean; + /** + * Whether to enable the rendering of bold text. + * + * @deprecated Use fontWeight and fontWeightBold instead. + */ + enableBold?: boolean; + + /** + * What character atlas implementation to use. The character atlas caches drawn characters, + * speeding up rendering significantly. However, it can introduce some minor rendering + * artifacts. + * + * - 'none': Don't use an atlas. + * - 'static': Generate an atlas when the terminal starts or is reconfigured. This atlas will + * only contain ASCII characters in 16 colors. + * - 'dynamic': Generate an atlas using a LRU cache as characters are requested. Limited to + * ASCII characters (for now), but supports 256 colors. For characters covered by the static + * cache, it's slightly slower in comparison, since there's more overhead involved in + * managing the cache. + * + * Currently defaults to 'static'. This option may be removed in the future. If it is, passed + * parameters will be ignored. + */ + experimentalCharAtlas?: 'none' | 'static' | 'dynamic'; + /** * The font size used to render text. */ @@ -681,6 +706,13 @@ declare module 'xterm' { */ dispose(): void; + /** + * Destroys the terminal and detaches it from the DOM. + * + * @deprecated Use dispose() instead. + */ + destroy(): void; + /** * Scroll the display of the terminal * @param amount The number of lines to scroll down (negative scroll up). @@ -743,7 +775,7 @@ declare module 'xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; + getOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -794,7 +826,7 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; + setOption(key: 'allowTransparency' | 'cancelEvents' | 'convertEol' | 'cursorBlink' | 'debug' | 'disableStdin' | 'enableBold' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. @@ -950,7 +982,7 @@ declare module 'xterm' { * * @param x The character index to get. */ - getCell(x: number): IBufferCell | undefined; + getCell(x: number): IBufferCell; /** * Gets the line as a string. Note that this is gets only the string for the line, not taking @@ -981,10 +1013,8 @@ declare module 'xterm' { } - - // Modifications to official .d.ts below -declare module 'xterm' { +declare module 'vscode-xterm' { interface TerminalCore { debug: boolean; @@ -1007,7 +1037,42 @@ declare module 'xterm' { fire(e: T): void; } + interface ISearchOptions { + /** + * Whether the find should be done as a regex. + */ + regex?: boolean; + /** + * Whether only whole words should match. + */ + wholeWord?: boolean; + /** + * Whether find should pay attention to case. + */ + caseSensitive?: boolean; + } + interface Terminal { _core: TerminalCore; + + webLinksInit(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions): void; + + /** + * Find the next instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The search term. + * @param findOptions Regex, whole word, and case sensitive options. + * @return Whether a result was found. + */ + findNext(term: string, findOptions: ISearchOptions): boolean; + + /** + * Find the previous instance of the term, then scroll to and select it. If it + * doesn't exist, do nothing. + * @param term The search term. + * @param findOptions Regex, whole word, and case sensitive options. + * @return Whether a result was found. + */ + findPrevious(term: string, findOptions: ISearchOptions): boolean; } -} \ No newline at end of file +} diff --git a/src/typings/xterm-addon-search.d.ts b/src/typings/xterm-addon-search.d.ts deleted file mode 100644 index 2f3be6f82b..0000000000 --- a/src/typings/xterm-addon-search.d.ts +++ /dev/null @@ -1,69 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -// HACK: gulp-tsb doesn't play nice with importing from typings -// import { Terminal, ITerminalAddon } from 'xterm'; - -declare module 'xterm-addon-search' { - /** - * Options for a search. - */ - export interface ISearchOptions { - /** - * Whether the search term is a regex. - */ - regex?: boolean; - - /** - * Whether to search for a whole word, the result is only valid if it's - * suppounded in "non-word" characters such as `_`, `(`, `)` or space. - */ - wholeWord?: boolean; - - /** - * Whether the search is case sensitive. - */ - caseSensitive?: boolean; - - /** - * Whether to do an indcremental search, this will expand the selection if it - * still matches the term the user typed. Note that this only affects - * `findNext`, not `findPrevious`. - */ - incremental?: boolean; - } - - /** - * An xterm.js addon that provides search functionality. - */ - export class SearchAddon { - /** - * Activates the addon - * @param terminal The terminal the addon is being loaded in. - */ - public activate(terminal: any): void; - - /** - * Disposes the addon. - */ - public dispose(): void; - - /** - * Search forwards for the next result that matches the search term and - * options. - * @param term The search term. - * @param searchOptions The options for the search. - */ - public findNext(term: string, searchOptions?: ISearchOptions): boolean; - - /** - * Search backwards for the previous result that matches the search term and - * options. - * @param term The search term. - * @param searchOptions The options for the search. - */ - public findPrevious(term: string, searchOptions?: ISearchOptions): boolean; - } -} diff --git a/src/typings/xterm-addon-web-links.d.ts b/src/typings/xterm-addon-web-links.d.ts deleted file mode 100644 index da348f8c82..0000000000 --- a/src/typings/xterm-addon-web-links.d.ts +++ /dev/null @@ -1,71 +0,0 @@ -/** - * Copyright (c) 2017 The xterm.js authors. All rights reserved. - * @license MIT - */ - -// HACK: gulp-tsb doesn't play nice with importing from typings -// import { Terminal, ITerminalAddon } from 'xterm'; -interface ILinkMatcherOptions { - /** - * The index of the link from the regex.match(text) call. This defaults to 0 - * (for regular expressions without capture groups). - */ - matchIndex?: number; - - /** - * A callback that validates whether to create an individual link, pass - * whether the link is valid to the callback. - */ - validationCallback?: (uri: string, callback: (isValid: boolean) => void) => void; - - /** - * A callback that fires when the mouse hovers over a link for a moment. - */ - tooltipCallback?: (event: MouseEvent, uri: string) => boolean | void; - - /** - * A callback that fires when the mouse leaves a link. Note that this can - * happen even when tooltipCallback hasn't fired for the link yet. - */ - leaveCallback?: () => void; - - /** - * The priority of the link matcher, this defines the order in which the link - * matcher is evaluated relative to others, from highest to lowest. The - * default value is 0. - */ - priority?: number; - - /** - * A callback that fires when the mousedown and click events occur that - * determines whether a link will be activated upon click. This enables - * only activating a link when a certain modifier is held down, if not the - * mouse event will continue propagation (eg. double click to select word). - */ - willLinkActivate?: (event: MouseEvent, uri: string) => boolean; -} - -declare module 'xterm-addon-web-links' { - /** - * An xterm.js addon that enables web links. - */ - export class WebLinksAddon { - /** - * Creates a new web links addon. - * @param handler The callback when the link is called. - * @param options Options for the link matcher. - */ - constructor(handler?: (event: MouseEvent, uri: string) => void, options?: ILinkMatcherOptions); - - /** - * Activates the addon - * @param terminal The terminal the addon is being loaded in. - */ - public activate(terminal: any): void; - - /** - * Disposes the addon. - */ - public dispose(): void; - } -} diff --git a/src/vs/base/browser/contextmenu.ts b/src/vs/base/browser/contextmenu.ts index c6cb3b7a80..a4434d722a 100644 --- a/src/vs/base/browser/contextmenu.ts +++ b/src/vs/base/browser/contextmenu.ts @@ -24,7 +24,7 @@ export class ContextSubMenu extends SubmenuAction { export interface IContextMenuDelegate { getAnchor(): HTMLElement | { x: number; y: number; width?: number; height?: number; }; - getActions(): ReadonlyArray; + getActions(): Array; getActionViewItem?(action: IAction): IActionViewItem | undefined; getActionsContext?(event?: IContextMenuEvent): any; getKeyBinding?(action: IAction): ResolvedKeybinding | undefined; diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index fd4bcebba8..02a6055c3a 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -11,7 +11,7 @@ import { TimeoutTimer } from 'vs/base/common/async'; import { CharCode } from 'vs/base/common/charCode'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import * as platform from 'vs/base/common/platform'; import { coalesce } from 'vs/base/common/arrays'; @@ -905,9 +905,10 @@ export const EventHelper = { } }; -export interface IFocusTracker extends Disposable { +export interface IFocusTracker { onDidFocus: Event; onDidBlur: Event; + dispose(): void; } export function saveParentsScrollTop(node: Element): number[] { @@ -928,20 +929,21 @@ export function restoreParentsScrollTop(node: Element, state: number[]): void { } } -class FocusTracker extends Disposable implements IFocusTracker { +class FocusTracker implements IFocusTracker { - private readonly _onDidFocus = this._register(new Emitter()); - public readonly onDidFocus: Event = this._onDidFocus.event; + private _onDidFocus = new Emitter(); + readonly onDidFocus: Event = this._onDidFocus.event; - private readonly _onDidBlur = this._register(new Emitter()); - public readonly onDidBlur: Event = this._onDidBlur.event; + private _onDidBlur = new Emitter(); + readonly onDidBlur: Event = this._onDidBlur.event; + + private disposables: IDisposable[] = []; constructor(element: HTMLElement | Window) { - super(); let hasFocus = isAncestor(document.activeElement, element); let loosingFocus = false; - const onFocus = () => { + let onFocus = () => { loosingFocus = false; if (!hasFocus) { hasFocus = true; @@ -949,7 +951,7 @@ class FocusTracker extends Disposable implements IFocusTracker { } }; - const onBlur = () => { + let onBlur = () => { if (hasFocus) { loosingFocus = true; window.setTimeout(() => { @@ -962,8 +964,14 @@ class FocusTracker extends Disposable implements IFocusTracker { } }; - this._register(domEvent(element, EventType.FOCUS, true)(onFocus)); - this._register(domEvent(element, EventType.BLUR, true)(onBlur)); + domEvent(element, EventType.FOCUS, true)(onFocus, null, this.disposables); + domEvent(element, EventType.BLUR, true)(onBlur, null, this.disposables); + } + + dispose(): void { + this.disposables = dispose(this.disposables); + this._onDidFocus.dispose(); + this._onDidBlur.dispose(); } } diff --git a/src/vs/base/browser/globalMouseMoveMonitor.ts b/src/vs/base/browser/globalMouseMoveMonitor.ts index b29d574cfd..f4fd8b5382 100644 --- a/src/vs/base/browser/globalMouseMoveMonitor.ts +++ b/src/vs/base/browser/globalMouseMoveMonitor.ts @@ -6,7 +6,7 @@ import * as dom from 'vs/base/browser/dom'; import { IframeUtils } from 'vs/base/browser/iframe'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; export interface IStandardMouseMoveEventData { leftButton: boolean; @@ -36,16 +36,24 @@ export function standardMouseMoveMerger(lastEvent: IStandardMouseMoveEventData, }; } -export class GlobalMouseMoveMonitor implements IDisposable { +export class GlobalMouseMoveMonitor extends Disposable { - private readonly hooks = new DisposableStore(); - private mouseMoveEventMerger: IEventMerger | null = null; - private mouseMoveCallback: IMouseMoveCallback | null = null; - private onStopCallback: IOnStopCallback | null = null; + private hooks: IDisposable[]; + private mouseMoveEventMerger: IEventMerger | null; + private mouseMoveCallback: IMouseMoveCallback | null; + private onStopCallback: IOnStopCallback | null; + + constructor() { + super(); + this.hooks = []; + this.mouseMoveEventMerger = null; + this.mouseMoveCallback = null; + this.onStopCallback = null; + } public dispose(): void { this.stopMonitoring(false); - this.hooks.dispose(); + super.dispose(); } public stopMonitoring(invokeStopCallback: boolean): void { @@ -55,10 +63,10 @@ export class GlobalMouseMoveMonitor implements IDisposable { } // Unhook - this.hooks.clear(); + this.hooks = dispose(this.hooks); this.mouseMoveEventMerger = null; this.mouseMoveCallback = null; - const onStopCallback = this.onStopCallback; + let onStopCallback = this.onStopCallback; this.onStopCallback = null; if (invokeStopCallback && onStopCallback) { @@ -66,8 +74,8 @@ export class GlobalMouseMoveMonitor implements IDisposable { } } - public isMonitoring(): boolean { - return !!this.mouseMoveEventMerger; + public isMonitoring() { + return this.hooks.length > 0; } public startMonitoring( @@ -85,32 +93,32 @@ export class GlobalMouseMoveMonitor implements IDisposable { let windowChain = IframeUtils.getSameOriginWindowChain(); for (const element of windowChain) { - this.hooks.add(dom.addDisposableThrottledListener(element.window.document, 'mousemove', + this.hooks.push(dom.addDisposableThrottledListener(element.window.document, 'mousemove', (data: R) => this.mouseMoveCallback!(data), (lastEvent: R, currentEvent) => this.mouseMoveEventMerger!(lastEvent, currentEvent as MouseEvent) )); - this.hooks.add(dom.addDisposableListener(element.window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); + this.hooks.push(dom.addDisposableListener(element.window.document, 'mouseup', (e: MouseEvent) => this.stopMonitoring(true))); } if (IframeUtils.hasDifferentOriginAncestor()) { let lastSameOriginAncestor = windowChain[windowChain.length - 1]; // We might miss a mouse up if it happens outside the iframe // This one is for Chrome - this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent: MouseEvent) => { + this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseout', (browserEvent: MouseEvent) => { let e = new StandardMouseEvent(browserEvent); if (e.target.tagName.toLowerCase() === 'html') { this.stopMonitoring(true); } })); // This one is for FF - this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent: MouseEvent) => { + this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document, 'mouseover', (browserEvent: MouseEvent) => { let e = new StandardMouseEvent(browserEvent); if (e.target.tagName.toLowerCase() === 'html') { this.stopMonitoring(true); } })); // This one is for IE - this.hooks.add(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent: MouseEvent) => { + this.hooks.push(dom.addDisposableListener(lastSameOriginAncestor.window.document.body, 'mouseleave', (browserEvent: MouseEvent) => { this.stopMonitoring(true); })); } diff --git a/src/vs/base/browser/hash.ts b/src/vs/base/browser/hash.ts new file mode 100644 index 0000000000..222332b2f8 --- /dev/null +++ b/src/vs/base/browser/hash.ts @@ -0,0 +1,15 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +export function createSHA1(content: string): Thenable { + if (typeof require !== 'undefined') { + const _crypto: typeof crypto = require.__$__nodeRequire('crypto'); + return Promise.resolve(_crypto['createHash']('sha1').update(content).digest('hex')); + } + return crypto.subtle.digest('SHA-1', new TextEncoder().encode(content)).then(buffer => { + // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string + return Array.prototype.map.call(new Uint8Array(buffer), (value: number) => `00${value.toString(16)}`.slice(-2)).join(''); + }); +} \ No newline at end of file diff --git a/src/vs/base/browser/htmlContentRenderer.ts b/src/vs/base/browser/htmlContentRenderer.ts index e4e315cd21..d400bbadf3 100644 --- a/src/vs/base/browser/htmlContentRenderer.ts +++ b/src/vs/base/browser/htmlContentRenderer.ts @@ -17,7 +17,7 @@ import { cloneAndChange } from 'vs/base/common/objects'; export interface IContentActionHandler { callback: (content: string, event?: IMouseEvent) => void; - readonly disposeables: IDisposable[]; + disposeables: IDisposable[]; } export interface RenderOptions { diff --git a/src/vs/base/browser/ui/actionbar/actionbar.ts b/src/vs/base/browser/ui/actionbar/actionbar.ts index 92345a2e45..ea3d32745f 100644 --- a/src/vs/base/browser/ui/actionbar/actionbar.ts +++ b/src/vs/base/browser/ui/actionbar/actionbar.ts @@ -6,7 +6,7 @@ import 'vs/css!./actionbar'; import * as platform from 'vs/base/common/platform'; import * as nls from 'vs/nls'; -import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose } from 'vs/base/common/lifecycle'; import { SelectBox, ISelectOptionItem, ISelectBoxOptions } from 'vs/base/browser/ui/selectBox/selectBox'; import { IAction, IActionRunner, Action, IActionChangeEvent, ActionRunner, IRunEvent } from 'vs/base/common/actions'; import * as DOM from 'vs/base/browser/dom'; @@ -16,14 +16,16 @@ import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; import { Event, Emitter } from 'vs/base/common/event'; +import { asArray } from 'vs/base/common/arrays'; -export interface IActionViewItem extends IDisposable { +export interface IActionViewItem { actionRunner: IActionRunner; setActionContext(context: any): void; render(element: HTMLElement): void; isEnabled(): boolean; focus(fromRight?: boolean): void; blur(): void; + dispose(): void; } export interface IBaseActionViewItemOptions { @@ -259,9 +261,6 @@ export class ActionViewItem extends BaseActionViewItem { this.label.setAttribute('role', 'menuitem'); } else { this.label.setAttribute('role', 'button'); - - // TODO @misolori remove before shipping stable - this.label.setAttribute('data-title', this._action.id); } } @@ -594,8 +593,8 @@ export class ActionBar extends Disposable implements IActionRunner { return this.domNode; } - push(arg: IAction | ReadonlyArray, options: IActionOptions = {}): void { - const actions: ReadonlyArray = Array.isArray(arg) ? arg : [arg]; + push(arg: IAction | IAction[], options: IActionOptions = {}): void { + const actions: IAction[] = asArray(arg); let index = types.isNumber(options.index) ? options.index : null; diff --git a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts index e96ce6f319..24f6dafa8a 100644 --- a/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts +++ b/src/vs/base/browser/ui/breadcrumbs/breadcrumbsWidget.ts @@ -9,7 +9,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { commonPrefixLength } from 'vs/base/common/arrays'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import 'vs/css!./breadcrumbsWidget'; @@ -134,14 +134,14 @@ export class BreadcrumbsWidget { } private _updateDimensions(dim: dom.Dimension): IDisposable { - const disposables = new DisposableStore(); - disposables.add(dom.modify(() => { + let disposables: IDisposable[] = []; + disposables.push(dom.modify(() => { this._dimension = dim; this._domNode.style.width = `${dim.width}px`; this._domNode.style.height = `${dim.height}px`; - disposables.add(this._updateScrollbar()); + disposables.push(this._updateScrollbar()); })); - return disposables; + return combinedDisposable(disposables); } private _updateScrollbar(): IDisposable { diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index e0fb0490dc..d51cb04707 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -7,7 +7,7 @@ import { SplitView, Orientation, ISplitViewStyles, IView as ISplitViewView } fro import { $ } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; import { IView } from 'vs/base/browser/ui/grid/gridview'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; export interface CenteredViewState { @@ -48,7 +48,7 @@ export interface ICenteredViewStyles extends ISplitViewStyles { background: Color; } -export class CenteredViewLayout implements IDisposable { +export class CenteredViewLayout { private splitView?: SplitView; private width: number = 0; @@ -56,7 +56,7 @@ export class CenteredViewLayout implements IDisposable { private style: ICenteredViewStyles; private didLayout = false; private emptyViews: ISplitViewView[] | undefined; - private readonly splitViewDisposables = new DisposableStore(); + private splitViewDisposables: IDisposable[] = []; constructor(private container: HTMLElement, private view: IView, public readonly state: CenteredViewState = { leftMarginRatio: GOLDEN_RATIO.leftMarginRatio, rightMarginRatio: GOLDEN_RATIO.rightMarginRatio }) { this.container.appendChild(this.view.element); @@ -117,13 +117,13 @@ export class CenteredViewLayout implements IDisposable { styles: this.style }); - this.splitViewDisposables.add(this.splitView.onDidSashChange(() => { + this.splitViewDisposables.push(this.splitView.onDidSashChange(() => { if (this.splitView) { this.state.leftMarginRatio = this.splitView.getViewSize(0) / this.width; this.state.rightMarginRatio = this.splitView.getViewSize(2) / this.width; } })); - this.splitViewDisposables.add(this.splitView.onDidSashReset(() => { + this.splitViewDisposables.push(this.splitView.onDidSashReset(() => { this.state.leftMarginRatio = GOLDEN_RATIO.leftMarginRatio; this.state.rightMarginRatio = GOLDEN_RATIO.rightMarginRatio; this.resizeMargins(); @@ -138,7 +138,7 @@ export class CenteredViewLayout implements IDisposable { if (this.splitView) { this.container.removeChild(this.splitView.el); } - this.splitViewDisposables.clear(); + this.splitViewDisposables = dispose(this.splitViewDisposables); if (this.splitView) { this.splitView.dispose(); } @@ -153,7 +153,7 @@ export class CenteredViewLayout implements IDisposable { } dispose(): void { - this.splitViewDisposables.dispose(); + this.splitViewDisposables = dispose(this.splitViewDisposables); if (this.splitView) { this.splitView.dispose(); diff --git a/src/vs/base/browser/ui/checkbox/checkbox.ts b/src/vs/base/browser/ui/checkbox/checkbox.ts index 8dbd54cf58..47adfc1499 100644 --- a/src/vs/base/browser/ui/checkbox/checkbox.ts +++ b/src/vs/base/browser/ui/checkbox/checkbox.ts @@ -12,7 +12,7 @@ import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as objects from 'vs/base/common/objects'; import { BaseActionViewItem } from 'vs/base/browser/ui/actionbar/actionbar'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; export interface ICheckboxOpts extends ICheckboxStyles { readonly actionClassName?: string; @@ -31,19 +31,19 @@ const defaultOpts = { export class CheckboxActionViewItem extends BaseActionViewItem { private checkbox: Checkbox; - private readonly disposables = new DisposableStore(); + private disposables: IDisposable[] = []; render(container: HTMLElement): void { this.element = container; - this.disposables.clear(); + this.disposables = dispose(this.disposables); this.checkbox = new Checkbox({ actionClassName: this._action.class, isChecked: this._action.checked, title: this._action.label }); - this.disposables.add(this.checkbox); - this.disposables.add(this.checkbox.onChange(() => this._action.checked = this.checkbox.checked, this)); + this.disposables.push(this.checkbox); + this.checkbox.onChange(() => this._action.checked = this.checkbox.checked, this, this.disposables); this.element.appendChild(this.checkbox.domNode); } @@ -64,9 +64,10 @@ export class CheckboxActionViewItem extends BaseActionViewItem { } dipsose(): void { - this.disposables.dispose(); + this.disposables = dispose(this.disposables); super.dispose(); } + } export class Checkbox extends Widget { diff --git a/src/vs/base/browser/ui/contextview/contextview.ts b/src/vs/base/browser/ui/contextview/contextview.ts index 5fca8286bb..bc28c7e3fd 100644 --- a/src/vs/base/browser/ui/contextview/contextview.ts +++ b/src/vs/base/browser/ui/contextview/contextview.ts @@ -5,7 +5,7 @@ import 'vs/css!./contextview'; import * as DOM from 'vs/base/browser/dom'; -import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Range } from 'vs/base/common/range'; export interface IAnchor { @@ -128,21 +128,21 @@ export class ContextView extends Disposable { this.container = container; this.container.appendChild(this.view); - const toDisposeOnSetContainer = new DisposableStore(); + const toDisposeOnSetContainer: IDisposable[] = []; ContextView.BUBBLE_UP_EVENTS.forEach(event => { - toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { this.onDOMEvent(e, false); })); }); ContextView.BUBBLE_DOWN_EVENTS.forEach(event => { - toDisposeOnSetContainer.add(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { + toDisposeOnSetContainer.push(DOM.addStandardDisposableListener(this.container!, event, (e: Event) => { this.onDOMEvent(e, true); }, true)); }); - this.toDisposeOnSetContainer = toDisposeOnSetContainer; + this.toDisposeOnSetContainer = combinedDisposable(toDisposeOnSetContainer); } } @@ -260,13 +260,12 @@ export class ContextView extends Disposable { } hide(data?: any): void { - const delegate = this.delegate; - this.delegate = null; - - if (delegate && delegate.onHide) { - delegate.onHide(data); + if (this.delegate && this.delegate.onHide) { + this.delegate.onHide(data); } + this.delegate = null; + if (this.toDisposeOnClean) { this.toDisposeOnClean.dispose(); this.toDisposeOnClean = null; diff --git a/src/vs/base/browser/ui/dropdown/dropdown.ts b/src/vs/base/browser/ui/dropdown/dropdown.ts index 0834eb8927..a3bd38835b 100644 --- a/src/vs/base/browser/ui/dropdown/dropdown.ts +++ b/src/vs/base/browser/ui/dropdown/dropdown.ts @@ -192,12 +192,12 @@ export interface IContextMenuProvider { } export interface IActionProvider { - getActions(): ReadonlyArray; + getActions(): IAction[]; } export interface IDropdownMenuOptions extends IBaseDropdownOptions { contextMenuProvider: IContextMenuProvider; - actions?: ReadonlyArray; + actions?: IAction[]; actionProvider?: IActionProvider; menuClassName?: string; } @@ -205,7 +205,7 @@ export interface IDropdownMenuOptions extends IBaseDropdownOptions { export class DropdownMenu extends BaseDropdown { private _contextMenuProvider: IContextMenuProvider; private _menuOptions: IMenuOptions; - private _actions: ReadonlyArray; + private _actions: IAction[]; private actionProvider?: IActionProvider; private menuClassName: string; @@ -226,7 +226,7 @@ export class DropdownMenu extends BaseDropdown { return this._menuOptions; } - private get actions(): ReadonlyArray { + private get actions(): IAction[] { if (this.actionProvider) { return this.actionProvider.getActions(); } @@ -234,7 +234,7 @@ export class DropdownMenu extends BaseDropdown { return this._actions; } - private set actions(actions: ReadonlyArray) { + private set actions(actions: IAction[]) { this._actions = actions; } @@ -275,7 +275,7 @@ export class DropdownMenuActionViewItem extends BaseActionViewItem { private clazz: string | undefined; private anchorAlignmentProvider: (() => AnchorAlignment) | undefined; - constructor(action: IAction, menuActions: ReadonlyArray, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); + constructor(action: IAction, menuActions: IAction[], contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); constructor(action: IAction, actionProvider: IActionProvider, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment); constructor(action: IAction, menuActionsOrProvider: any, contextMenuProvider: IContextMenuProvider, actionViewItemProvider: IActionViewItemProvider | undefined, actionRunner: IActionRunner, keybindings: ((action: IAction) => ResolvedKeybinding | undefined) | undefined, clazz: string | undefined, anchorAlignmentProvider?: () => AnchorAlignment) { super(null, action); diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 092ab6f41c..4e2d1a196e 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -5,7 +5,7 @@ import 'vs/css!./gridview'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles } from './gridview'; import { Event, Emitter } from 'vs/base/common/event'; @@ -191,10 +191,12 @@ export interface IGridOptions { proportionalLayout?: boolean; } -export class Grid extends Disposable { +export class Grid implements IDisposable { protected gridview: GridView; private views = new Map(); + private disposables: IDisposable[] = []; + get orientation(): Orientation { return this.gridview.orientation; } set orientation(orientation: Orientation) { this.gridview.orientation = orientation; } @@ -212,11 +214,10 @@ export class Grid extends Disposable { sashResetSizing: Sizing = Sizing.Distribute; constructor(view: T, options: IGridOptions = {}) { - super(); this.gridview = new GridView(options); - this._register(this.gridview); + this.disposables.push(this.gridview); - this._register(this.gridview.onDidSashReset(this.doResetViewSize, this)); + this.gridview.onDidSashReset(this.doResetViewSize, this, this.disposables); this._addView(view, 0, [0]); } @@ -374,6 +375,10 @@ export class Grid extends Disposable { this.gridview.distributeViewSizes(parentLocation); } } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export interface ISerializableView extends IView { diff --git a/src/vs/base/browser/ui/inputbox/inputBox.ts b/src/vs/base/browser/ui/inputbox/inputBox.ts index 44fc80ba56..1d72186b6b 100644 --- a/src/vs/base/browser/ui/inputbox/inputBox.ts +++ b/src/vs/base/browser/ui/inputbox/inputBox.ts @@ -28,8 +28,7 @@ export interface IInputOptions extends IInputBoxStyles { readonly type?: string; readonly validationOptions?: IInputValidationOptions; readonly flexibleHeight?: boolean; - readonly actions?: ReadonlyArray; - + readonly actions?: IAction[]; // {{SQL CARBON EDIT}} Candidate for addition to vscode readonly min?: string; @@ -100,7 +99,7 @@ export class InputBox extends Widget { private placeholder: string; private ariaLabel: string; private validation?: IInputValidator; - private state: 'idle' | 'open' | 'closed' = 'idle'; + private state: string | null = 'idle'; private cachedHeight: number | null; // {{SQL CARBON EDIT}} - Add showValidationMessage and set inputBackground, inputForeground, and inputBorder as protected @@ -423,6 +422,8 @@ export class InputBox extends Widget { let div: HTMLElement; let layout = () => div.style.width = dom.getTotalWidth(this.element) + 'px'; + this.state = 'open'; + this.contextViewProvider.showContextView({ getAnchor: () => this.element, anchorAlignment: AnchorAlignment.RIGHT, @@ -453,25 +454,18 @@ export class InputBox extends Widget { return null; }, - onHide: () => { - this.state = 'closed'; - }, layout: layout }); - - this.state = 'open'; } private _hideMessage(): void { - if (!this.contextViewProvider) { + if (!this.contextViewProvider || this.state !== 'open') { return; } - if (this.state === 'open') { - this.contextViewProvider.hideContextView(); - } - this.state = 'idle'; + + this.contextViewProvider.hideContextView(); } private onValueChange(): void { @@ -561,7 +555,7 @@ export class InputBox extends Widget { this.contextViewProvider = undefined; this.message = null; this.validation = undefined; - this.state = null!; // StrictNullOverride: nulling out ok in dispose + this.state = null; this.actionbar = undefined; super.dispose(); diff --git a/src/vs/base/browser/ui/menu/menu.css b/src/vs/base/browser/ui/menu/menu.css index 15660767c2..aec27d7afd 100644 --- a/src/vs/base/browser/ui/menu/menu.css +++ b/src/vs/base/browser/ui/menu/menu.css @@ -133,7 +133,7 @@ } .monaco-menu .monaco-action-bar.vertical .action-item { - border: thin solid transparent; /* prevents jumping behaviour on hover or focus */ + border: 1px solid transparent; /* prevents jumping behaviour on hover or focus */ } diff --git a/src/vs/base/browser/ui/menu/menu.ts b/src/vs/base/browser/ui/menu/menu.ts index 3fda64e3d9..d65d930df3 100644 --- a/src/vs/base/browser/ui/menu/menu.ts +++ b/src/vs/base/browser/ui/menu/menu.ts @@ -12,7 +12,7 @@ import { ResolvedKeybinding, KeyCode } from 'vs/base/common/keyCodes'; import { addClass, EventType, EventHelper, EventLike, removeTabIndexAndUpdateFocus, isAncestor, hasClass, addDisposableListener, removeClass, append, $, addClasses, removeClasses } from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable'; @@ -59,7 +59,7 @@ export interface IMenuStyles { } export class SubmenuAction extends Action { - constructor(label: string, public entries: ReadonlyArray, cssClass?: string) { + constructor(label: string, public entries: Array, cssClass?: string) { super(!!cssClass ? cssClass : 'submenu', label, '', true); } } @@ -71,14 +71,15 @@ interface ISubMenuData { export class Menu extends ActionBar { private mnemonics: Map>; - private readonly menuDisposables: DisposableStore; + private menuDisposables: IDisposable[]; private scrollableElement: DomScrollableElement; private menuElement: HTMLElement; private scrollTopHold: number | undefined; private readonly _onScroll: Emitter; - constructor(container: HTMLElement, actions: ReadonlyArray, options: IMenuOptions = {}) { + constructor(container: HTMLElement, actions: IAction[], options: IMenuOptions = {}) { + addClass(container, 'monaco-menu-container'); container.setAttribute('role', 'presentation'); const menuElement = document.createElement('div'); @@ -102,7 +103,7 @@ export class Menu extends ActionBar { this.actionsList.tabIndex = 0; - this.menuDisposables = this._register(new DisposableStore()); + this.menuDisposables = []; addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { const event = new StandardKeyboardEvent(e); @@ -114,7 +115,7 @@ export class Menu extends ActionBar { }); if (options.enableMnemonics) { - this.menuDisposables.add(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { + this.menuDisposables.push(addDisposableListener(menuElement, EventType.KEY_DOWN, (e) => { const key = e.key.toLocaleLowerCase(); if (this.mnemonics.has(key)) { EventHelper.stop(e, true); @@ -216,9 +217,9 @@ export class Menu extends ActionBar { menuElement.style.maxHeight = `${Math.max(10, window.innerHeight - container.getBoundingClientRect().top - 30)}px`; - this.menuDisposables.add(this.scrollableElement.onScroll(() => { + this.scrollableElement.onScroll(() => { this._onScroll.fire(); - }, this)); + }, this, this.menuDisposables); this._register(addDisposableListener(this.menuElement, EventType.SCROLL, (e: ScrollEvent) => { if (this.scrollTopHold !== undefined) { @@ -556,7 +557,7 @@ class BaseMenuActionViewItem extends BaseActionViewItem { const isSelected = this.element && hasClass(this.element, 'focused'); const fgColor = isSelected && this.menuStyle.selectionForegroundColor ? this.menuStyle.selectionForegroundColor : this.menuStyle.foregroundColor; const bgColor = isSelected && this.menuStyle.selectionBackgroundColor ? this.menuStyle.selectionBackgroundColor : this.menuStyle.backgroundColor; - const border = isSelected && this.menuStyle.selectionBorderColor ? `thin solid ${this.menuStyle.selectionBorderColor}` : null; + const border = isSelected && this.menuStyle.selectionBorderColor ? `1px solid ${this.menuStyle.selectionBorderColor}` : null; this.item.style.color = fgColor ? `${fgColor}` : null; this.check.style.backgroundColor = fgColor ? `${fgColor}` : null; @@ -574,14 +575,14 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { private mysubmenu: Menu | null; private submenuContainer: HTMLElement | undefined; private submenuIndicator: HTMLElement; - private readonly submenuDisposables = this._register(new DisposableStore()); + private submenuDisposables: IDisposable[] = []; private mouseOver: boolean; private showScheduler: RunOnceScheduler; private hideScheduler: RunOnceScheduler; constructor( action: IAction, - private submenuActions: ReadonlyArray, + private submenuActions: IAction[], private parentData: ISubMenuData, private submenuOptions?: IMenuOptions ) { @@ -674,7 +675,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { this.parentData.submenu = undefined; if (this.submenuContainer) { - this.submenuDisposables.clear(); + this.submenuDisposables = dispose(this.submenuDisposables); this.submenuContainer = undefined; } } @@ -707,7 +708,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { this.submenuContainer.style.top = `${this.element.offsetTop - this.parentData.parent.scrollOffset - paddingTop}px`; } - this.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => { + this.submenuDisposables.push(addDisposableListener(this.submenuContainer, EventType.KEY_UP, e => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.LeftArrow)) { EventHelper.stop(e, true); @@ -719,12 +720,12 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { this.parentData.submenu = undefined; } - this.submenuDisposables.clear(); + this.submenuDisposables = dispose(this.submenuDisposables); this.submenuContainer = undefined; } })); - this.submenuDisposables.add(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => { + this.submenuDisposables.push(addDisposableListener(this.submenuContainer, EventType.KEY_DOWN, e => { let event = new StandardKeyboardEvent(e); if (event.equals(KeyCode.LeftArrow)) { EventHelper.stop(e, true); @@ -732,7 +733,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { })); - this.submenuDisposables.add(this.parentData.submenu.onDidCancel(() => { + this.submenuDisposables.push(this.parentData.submenu.onDidCancel(() => { this.parentData.parent.focus(); if (this.parentData.submenu) { @@ -740,7 +741,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { this.parentData.submenu = undefined; } - this.submenuDisposables.clear(); + this.submenuDisposables = dispose(this.submenuDisposables); this.submenuContainer = undefined; })); @@ -780,6 +781,7 @@ class SubmenuMenuActionViewItem extends BaseMenuActionViewItem { } if (this.submenuContainer) { + this.submenuDisposables = dispose(this.submenuDisposables); this.submenuContainer = undefined; } } diff --git a/src/vs/base/browser/ui/menu/menubar.ts b/src/vs/base/browser/ui/menu/menubar.ts index 8589ca2173..c534ba5ba0 100644 --- a/src/vs/base/browser/ui/menu/menubar.ts +++ b/src/vs/base/browser/ui/menu/menubar.ts @@ -15,7 +15,7 @@ import { ActionRunner, IAction, IActionRunner } from 'vs/base/common/actions'; import { RunOnceScheduler } from 'vs/base/common/async'; import { Event, Emitter } from 'vs/base/common/event'; import { KeyCode, ResolvedKeybinding } from 'vs/base/common/keyCodes'; -import { Disposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { withNullAsUndefined } from 'vs/base/common/types'; import { asArray } from 'vs/base/common/arrays'; @@ -29,7 +29,7 @@ export interface IMenuBarOptions { } export interface MenuBarMenu { - actions: ReadonlyArray; + actions: IAction[]; label: string; } @@ -48,7 +48,7 @@ export class MenuBar extends Disposable { buttonElement: HTMLElement; titleElement: HTMLElement; label: string; - actions?: ReadonlyArray; + actions?: IAction[]; }[]; private overflowMenu: { @@ -896,7 +896,7 @@ interface IModifierKeyStatus { class ModifierKeyEmitter extends Emitter { - private readonly _subscriptions = new DisposableStore(); + private _subscriptions: IDisposable[] = []; private _keyStatus: IModifierKeyStatus; private static instance: ModifierKeyEmitter; @@ -909,7 +909,7 @@ class ModifierKeyEmitter extends Emitter { ctrlKey: false }; - this._subscriptions.add(domEvent(document.body, 'keydown', true)(e => { + this._subscriptions.push(domEvent(document.body, 'keydown', true)(e => { const event = new StandardKeyboardEvent(e); if (e.altKey && !this._keyStatus.altKey) { @@ -933,7 +933,7 @@ class ModifierKeyEmitter extends Emitter { } })); - this._subscriptions.add(domEvent(document.body, 'keyup', true)(e => { + this._subscriptions.push(domEvent(document.body, 'keyup', true)(e => { if (!e.altKey && this._keyStatus.altKey) { this._keyStatus.lastKeyReleased = 'alt'; } else if (!e.ctrlKey && this._keyStatus.ctrlKey) { @@ -957,21 +957,21 @@ class ModifierKeyEmitter extends Emitter { } })); - this._subscriptions.add(domEvent(document.body, 'mousedown', true)(e => { + this._subscriptions.push(domEvent(document.body, 'mousedown', true)(e => { this._keyStatus.lastKeyPressed = undefined; })); - this._subscriptions.add(domEvent(document.body, 'mouseup', true)(e => { + this._subscriptions.push(domEvent(document.body, 'mouseup', true)(e => { this._keyStatus.lastKeyPressed = undefined; })); - this._subscriptions.add(domEvent(document.body, 'mousemove', true)(e => { + this._subscriptions.push(domEvent(document.body, 'mousemove', true)(e => { if (e.buttons) { this._keyStatus.lastKeyPressed = undefined; } })); - this._subscriptions.add(domEvent(window, 'blur')(e => { + this._subscriptions.push(domEvent(window, 'blur')(e => { this._keyStatus.lastKeyPressed = undefined; this._keyStatus.lastKeyReleased = undefined; this._keyStatus.altKey = false; @@ -992,6 +992,6 @@ class ModifierKeyEmitter extends Emitter { dispose() { super.dispose(); - this._subscriptions.dispose(); + this._subscriptions = dispose(this._subscriptions); } } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css index d9cc1b7a4f..d583733048 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.css @@ -1,7 +1,7 @@ @font-face { font-family: "octicons"; - src: url("./octicons.ttf?1b0f2a9535896866c74dd24eedeb4374") format("truetype"), -url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg"); + src: url("./octicons.ttf?91284a5a76ea88faeb754359b7f7cd03") format("truetype"), +url("./octicons.svg?91284a5a76ea88faeb754359b7f7cd03#octicons") format("svg"); } .octicon, .mega-octicon { @@ -235,14 +235,10 @@ url("./octicons.svg?1b0f2a9535896866c74dd24eedeb4374#octicons") format("svg"); .octicon-zap:before { content: "\26a1" } .octicon-archive:before { content: "\f101" } .octicon-arrow-both:before { content: "\f102" } -.octicon-error:before { content: "\f103" } -.octicon-eye-closed:before { content: "\f104" } -.octicon-fold-down:before { content: "\f105" } -.octicon-fold-up:before { content: "\f106" } -.octicon-github-action:before { content: "\f107" } -.octicon-info-outline:before { content: "\f108" } -.octicon-play:before { content: "\f109" } -.octicon-remote:before { content: "\f10a" } -.octicon-request-changes:before { content: "\f10b" } -.octicon-smiley-outline:before { content: "\f10c" } -.octicon-warning:before { content: "\f10d" } +.octicon-eye-closed:before { content: "\f103" } +.octicon-fold-down:before { content: "\f104" } +.octicon-fold-up:before { content: "\f105" } +.octicon-github-action:before { content: "\f106" } +.octicon-play:before { content: "\f107" } +.octicon-remote:before { content: "\f108" } +.octicon-request-changes:before { content: "\f109" } diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg index 3f4ab4f180..af83960978 100644 --- a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg +++ b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.svg @@ -42,10 +42,10 @@ horiz-adv-x="625" d=" M312.5 632.5L0 257.5H187.5V7.5H437.5V257.5H625L312.5 632.5z" /> + horiz-adv-x="1000" d=" M898.75 -91.875L687.5 382.5V632.5H750V695H187.5V632.5H250V382.5L39.375 -91.875A62.5 62.5 0 0 1 96.25 -180H842.5C887.5000000000001 -180 917.5 -133.125 899.375 -91.875H898.75zM234.375 195L312.5 382.5V632.5H625V382.5L703.125 195H234.375zM500 320H562.5V257.5H500V320zM437.5 382.5H375V445H437.5V382.5zM437.5 570H500V507.5H437.5V570zM437.5 757.5H375V820H437.5V757.5z" /> + horiz-adv-x="937.5" d=" M875 70V7.5H0V70L45.625 106.25C93.75 154.375 96.25 265.6249999999999 120 382.5C168.125 618.125 375 695 375 695C375 729.375 403.125 757.5 437.5 757.5S500 729.375 500 695C500 695 711.875 618.125 760 382.5C783.7500000000001 265.0000000000001 786.25 153.75 834.375 106.25L875.625 70H875zM437.5 -180C506.8749999999999 -180 562.5 -124.375 562.5 -55H312.5C312.5 -124.375 368.125 -180 437.5 -180z" /> @@ -166,11 +166,8 @@ - - + horiz-adv-x="875" d=" M393.75 464.375A58.875 58.875 0 0 0 376.25 508.125C376.25 525.625 381.875 540.625 393.75 551.875C405.625 563.125 420 569.375 437.5 569.375C455 569.375 470 563.75 481.25 551.875C492.5 540 498.75 525.625 498.75 508.125C498.75 490.6249999999999 493.1250000000001 475.625 481.25 464.375A62.5 62.5 0 0 0 437.5 445.625C420 445.625 405 452.5 393.75 464.375zM500 320.625C498.75 336.25 493.125 350.625 480.625 363.75C468.125 375.625 454.3750000000001 382.5 437.5 383.125H375C358.125 381.875 345 375 331.8750000000001 363.75C319.375 351.25 313.1250000000001 336.25 312.5000000000001 320.625H375.0000000000001V133.125C376.2500000000001 116.25 381.8750000000001 101.875 394.3750000000001 90C406.8750000000001 77.5000000000001 420.625 70.625 437.5 70.625H500C516.875 70.625 530 77.5 543.125 90C555.6249999999999 101.875 561.875 116.25 562.5 133.125H500V321.25V320.625zM437.5 676.25C241.25 676.25 81.25 517.5 81.25 321.2500000000001C81.25 125 241.25 -35 437.5 -35S793.75 124.3750000000001 793.75 321.2500000000001C793.75 518.125 633.7499999999999 676.875 437.5 676.875V676.25zM437.5 758.75C678.75 758.75 875 562.5 875 321.25S678.75 -116.25 437.5 -116.25S0 78.75 0 321.25S196.25 758.75 437.5 758.75z" /> @@ -398,7 +392,7 @@ unicode="" horiz-adv-x="1000" d=" M625 745V695L656.25 632.5L375 445H137.5C110 445 95.625 411.875 116.25 391.25L312.5 195L62.5 -117.5L375 132.5L571.25 -63.75A31.25 31.25 0 0 1 625 -42.5V195L812.5 476.25L875 445H925C952.5 445 966.875 478.125 946.25 498.75L678.75 766.25A31.25 31.25 0 0 1 625 745z" /> + horiz-adv-x="937.5" d=" M375 695H562.5V195H375z M125 695H312.5V-55H125z M625 695H812.5V70H625z M875 820H62.5C25 820 0 795 0 757.5V-117.5C0 -155 25 -180 62.5 -180H875C912.5 -180 937.5 -155 937.5 -117.5V757.5C937.5 795 912.5 820 875 820zM875 -117.5H62.5V757.5H875z" /> @@ -428,7 +422,7 @@ unicode="" horiz-adv-x="1000" d=" M299.375 438.125C315 453.75 315 480 299.375 495.625C279.375 516.25 269.3750000000001 543.125 269.3750000000001 570C269.3750000000001 596.875 279.3750000000001 623.75 299.3750000000001 644.375C315.0000000000001 660.625 315.0000000000001 686.25 299.3750000000001 701.875A38.3125 38.3125 0 0 1 271.2500000000001 713.75C261.2500000000001 713.75 250.6250000000001 710 243.1250000000001 701.875C207.5000000000001 665.625 190 617.5 190 570C190 522.5 208.125 474.375 243.1250000000001 438.1250000000001C258.7500000000001 422.5000000000001 284.3750000000001 422.5000000000001 299.3750000000001 438.1250000000001zM145.625 787.5A40.6875 40.6875 0 0 1 88.125 787.5C30 727.5 0.625 648.75 0.625 570.625C0.625 491.875 30 413.125 88.125 353.125C103.75 336.875 129.375 336.875 145 353.125S160.625 395.625 145 411.875C102.5 455.6249999999999 81.25 513.125 81.25 570.625C81.25 628.1249999999999 102.5 685.6249999999999 145 729.3749999999999A41.25 41.25 0 0 1 145.625 787.4999999999999zM501.25 468.7500000000001A101.25 101.25 0 1 1 400 570C399.3750000000001 514.375 445 468.75 501.25 468.75zM911.875 786.875A39.25 39.25 0 0 1 855 786.875C839.375 770.625 839.375 744.375 855 728.125C897.5 684.375 918.75 626.875 918.75 569.375C918.75 511.875 897.5 455 855 410.625C839.375 394.375 839.375 368.1250000000001 855 351.875A40.6875 40.6875 0 0 1 912.5 351.875C970.625 411.875 1000 490.625 1000 569.375A315.5 315.5 0 0 1 911.875 786.875zM501.25 387.5C475.6249999999999 387.5 449.375 393.75 426.25 406.25L229.375 -116.8749999999999H322.5L376.25 -54.3749999999999H626.25L678.75 -116.8749999999999H771.875L575.625 406.25C551.875 393.75 526.8750000000001 387.5 501.2500000000001 387.5zM500.625 357.5L563.75 132.5H438.75L500.625 357.5zM376.25 8.125L438.75 70.625H563.75L626.25 8.125H376.25zM700.625 701.875C685 686.25 685 660 700.625 644.375C720.6250000000001 623.75 730.6250000000001 596.875 730.6250000000001 570C730.6250000000001 543.125 720.6250000000001 516.25 700.625 495.6250000000001C685 479.3750000000001 685 453.7500000000001 700.625 438.1250000000001A39.375 39.375 0 0 1 756.8750000000001 438.1250000000001C792.5000000000001 474.3750000000001 810 522.5 810 570C810 617.5 792.5000000000001 665.625 756.8750000000001 701.875A39.625 39.625 0 0 1 700.625 701.875z" /> - + horiz-adv-x="1000" d=" M500 820C223.75 820 0 596.25 0 320S223.75 -180 500 -180S1000 43.75 1000 320S776.25 820 500 820zM800.6249999999999 19.375A419.99999999999994 419.99999999999994 0 0 0 664.9999999999999 -71.25C613.1249999999999 -93.75 557.4999999999999 -104.375 499.9999999999999 -104.375C442.4999999999999 -104.375 386.8749999999999 -93.75 334.9999999999999 -71.25C284.3749999999999 -50 238.1249999999999 -19.375 199.3749999999999 19.375A423.31249999999994 423.31249999999994 0 0 0 108.7499999999999 155A411.875 411.875 0 0 0 75.625 320C75.625 377.5 86.25 433.1250000000001 108.75 485.0000000000001C130 535.625 160.625 581.875 199.375 620.625C238.125 659.375 284.375 690 335 711.25A411.875 411.875 0 0 0 500 744.375C557.5 744.375 613.125 733.75 665 711.25C715.6250000000001 690 761.8750000000001 659.375 800.625 620.625C839.375 581.875 870 535.625 891.25 485.0000000000001C913.75 433.1250000000001 924.375 377.5000000000001 924.375 320C924.375 262.5 913.75 206.875 891.25 155C870 104.3749999999999 839.375 58.1249999999999 800.625 19.375zM250 395V431.875C250 473.125 283.125 506.25 325 506.25H361.875C403.125 506.25 436.25 473.125 436.25 431.8750000000001V395.0000000000001C436.25 353.1250000000001 403.125 320.0000000000001 361.8750000000001 320.0000000000001H325C283.125 320 250 353.125 250 395zM562.5 395V431.875C562.5 473.125 595.625 506.25 637.5 506.25H674.375C715.625 506.25 748.7499999999999 473.125 748.7499999999999 431.8750000000001V395.0000000000001C748.7499999999999 353.1250000000001 715.625 320.0000000000001 674.375 320.0000000000001H637.5C595.625 320 562.5 353.125 562.5 395zM812.5 195C767.5 77.5000000000001 630.625 7.5 500 7.5S232.5 78.1249999999999 187.5 195C178.75 219.375 201.875 257.5 228.75 257.5H765.625C791.25 257.5 821.25 219.375 812.5 195z" /> @@ -534,7 +525,7 @@ horiz-adv-x="1000" d=" M998.75 309.375L938.125 -62.5000000000001C927.5 -148.75 820.625 -180 750 -180H355.625C343.125 -180 331.8750000000001 -176.875 322.5 -171.25L232.5 -117.5H125C58.75 -117.5 0 -58.75 0 7.5V257.5C0 323.7500000000001 58.75 383.75 125 382.5H250C306.875 382.5 336.875 410.625 399.3750000000001 479.375C456.2500000000001 541.875 454.3750000000001 591.875 438.7500000000001 683.75C433.75 715 442.5 746.25 465 772.5C489.375 801.875 526.25 820 562.5 820C676.875 820 750 588.125 750 506.875L748.75 445.625H876.25C948.75 445.625 998.1249999999998 395.625 1000 322.5C1000 315.625 998.75 309.375 998.75 309.375zM875.625 383.75H751.25C707.5 383.75 686.875 401.25 686.875 444.375L688.75 508.75C688.75 588.125 615.625 758.75 563.75 758.75C532.5 758.75 496.2499999999999 727.5 501.25 696.25C516.875 597.5 522.5 522.5 445.625 437.5C381.875 366.875 335 320 250 320V-55L354.375 -117.5H750C795.625 -117.5 871.875 -98.125 875 -55L876.25 -53.75L938.75 321.25C936.875 361.25 914.9999999999998 383.75 876.25 383.75H875.625z" /> + horiz-adv-x="1000" d=" M280 365.625C296.25 349.3750000000001 360.0000000000001 282.5 360.0000000000001 282.5L395 318.75L340 375.6250000000001L445.6250000000001 488.125S398.1250000000001 534.375 418.7500000000001 516.25C438.7500000000001 590.625 420.6250000000001 673.125 364.3750000000001 731.25C308.125 788.75 228.75 807.5 157.5 788.125L278.125 663.125L246.2500000000001 540.625L128.1250000000001 508.125L7.5 633.125C-11.875 559.375 6.25 477.5 62.5 420C121.25 358.75 205.625 341.25 280 365.625zM682.5000000000001 244.3750000000001L536.8750000000001 100.6250000000001L776.8750000000001 -148.1249999999999C796.2500000000001 -168.7499999999999 822.5000000000001 -178.7499999999999 848.1250000000001 -178.7499999999999C873.7500000000001 -178.7499999999999 899.3750000000001 -168.7499999999999 919.3750000000002 -148.1249999999999C958.7500000000002 -107.4999999999999 958.7500000000002 -41.875 919.3750000000002 -1.2499999999999L682.5000000000001 244.3750000000001zM1000 661.875L846.875 820L395.625 353.75L450.625 296.875L181.25 18.1250000000001L119.375 -14.9999999999999L32.5 -156.8749999999998L54.375 -179.9999999999998L191.8750000000001 -89.9999999999998L223.7500000000001 -26.2499999999999L493.75 252.5L548.7500000000001 195.625L1000 661.875z" /> @@ -565,9 +556,6 @@ - diff --git a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf index 4eb17f9045..8c29d33830 100644 Binary files a/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf and b/src/vs/base/browser/ui/octiconLabel/octicons/octicons.ttf differ diff --git a/src/vs/base/browser/ui/sash/sash.ts b/src/vs/base/browser/ui/sash/sash.ts index 44f97573d4..37a058e709 100644 --- a/src/vs/base/browser/ui/sash/sash.ts +++ b/src/vs/base/browser/ui/sash/sash.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./sash'; -import { IDisposable, dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { isIPad } from 'vs/base/browser/browser'; import { isMacintosh } from 'vs/base/common/platform'; import * as types from 'vs/base/common/types'; @@ -95,14 +95,14 @@ export class Sash extends Disposable { linkedSash: Sash | undefined = undefined; - private readonly orthogonalStartSashDisposables = this._register(new DisposableStore()); + private orthogonalStartSashDisposables: IDisposable[] = []; private _orthogonalStartSash: Sash | undefined; get orthogonalStartSash(): Sash | undefined { return this._orthogonalStartSash; } set orthogonalStartSash(sash: Sash | undefined) { - this.orthogonalStartSashDisposables.clear(); + this.orthogonalStartSashDisposables = dispose(this.orthogonalStartSashDisposables); if (sash) { - this.orthogonalStartSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalStartSashEnablementChange, this)); + sash.onDidEnablementChange(this.onOrthogonalStartSashEnablementChange, this, this.orthogonalStartSashDisposables); this.onOrthogonalStartSashEnablementChange(sash.state); } else { this.onOrthogonalStartSashEnablementChange(SashState.Disabled); @@ -111,14 +111,14 @@ export class Sash extends Disposable { this._orthogonalStartSash = sash; } - private readonly orthogonalEndSashDisposables = this._register(new DisposableStore()); + private orthogonalEndSashDisposables: IDisposable[] = []; private _orthogonalEndSash: Sash | undefined; get orthogonalEndSash(): Sash | undefined { return this._orthogonalEndSash; } set orthogonalEndSash(sash: Sash | undefined) { - this.orthogonalEndSashDisposables.clear(); + this.orthogonalEndSashDisposables = dispose(this.orthogonalEndSashDisposables); if (sash) { - this.orthogonalEndSashDisposables.add(sash.onDidEnablementChange(this.onOrthogonalEndSashEnablementChange, this)); + sash.onDidEnablementChange(this.onOrthogonalEndSashEnablementChange, this, this.orthogonalEndSashDisposables); this.onOrthogonalEndSashEnablementChange(sash.state); } else { this.onOrthogonalEndSashEnablementChange(SashState.Disabled); @@ -384,6 +384,9 @@ export class Sash extends Disposable { dispose(): void { super.dispose(); + this.orthogonalStartSashDisposables = dispose(this.orthogonalStartSashDisposables); + this.orthogonalEndSashDisposables = dispose(this.orthogonalEndSashDisposables); + if (this.el && this.el.parentElement) { this.el.parentElement.removeChild(this.el); } diff --git a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts index 10c3d6dc1a..eda689c79a 100644 --- a/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts +++ b/src/vs/base/browser/ui/scrollbar/abstractScrollbar.ts @@ -108,12 +108,6 @@ export abstract class AbstractScrollbar extends Widget { this._sliderMouseDown(e, () => { /*nothing to do*/ }); } }); - - this.onclick(this.slider.domNode, e => { - if (e.leftButton) { - e.stopPropagation(); - } - }); } // ----------------- Update state diff --git a/src/vs/base/browser/ui/selectBox/selectBox.ts b/src/vs/base/browser/ui/selectBox/selectBox.ts index 2ce97a42ce..21c83e4cb1 100644 --- a/src/vs/base/browser/ui/selectBox/selectBox.ts +++ b/src/vs/base/browser/ui/selectBox/selectBox.ts @@ -14,12 +14,11 @@ import { IListStyles } from 'vs/base/browser/ui/list/listWidget'; import { SelectBoxNative } from 'vs/base/browser/ui/selectBox/selectBoxNative'; import { SelectBoxList } from 'vs/base/browser/ui/selectBox/selectBoxCustom'; import { isMacintosh } from 'vs/base/common/platform'; -import { IDisposable } from 'vs/base/common/lifecycle'; // Public SelectBox interface - Calls routed to appropriate select implementation class -export interface ISelectBoxDelegate extends IDisposable { +export interface ISelectBoxDelegate { // Public SelectBox Interface readonly onDidSelect: Event; @@ -28,6 +27,7 @@ export interface ISelectBoxDelegate extends IDisposable { setAriaLabel(label: string): void; focus(): void; blur(): void; + dispose(): void; // Delegated Widget interface render(container: HTMLElement): void; @@ -147,4 +147,5 @@ export class SelectBox extends Widget implements ISelectBoxDelegate { return option; } + } diff --git a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts index 0c80f04675..ed5149a0cd 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxCustom.ts @@ -5,7 +5,7 @@ import 'vs/css!./selectBoxCustom'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { KeyCode, KeyCodeUtils } from 'vs/base/common/keyCodes'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -85,7 +85,7 @@ class SelectListRenderer implements IListRenderer { +export class SelectBoxList implements ISelectBoxDelegate, IListVirtualDelegate { private static readonly DEFAULT_DROPDOWN_MINIMUM_BOTTOM_MARGIN = 32; private static readonly DEFAULT_DROPDOWN_MINIMUM_TOP_MARGIN = 2; @@ -98,6 +98,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi private options: ISelectOptionItem[]; private selected: number; private readonly _onDidSelect: Emitter; + private toDispose: IDisposable[]; private styles: ISelectBoxStyles; private listRenderer: SelectListRenderer; private contextViewProvider: IContextViewProvider; @@ -116,7 +117,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi constructor(options: ISelectOptionItem[], selected: number, contextViewProvider: IContextViewProvider, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) { - super(); + this.toDispose = []; this._isVisible = false; this.selectBoxOptions = selectBoxOptions || Object.create(null); @@ -136,7 +137,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } this._onDidSelect = new Emitter(); - this._register(this._onDidSelect); + this.toDispose.push(this._onDidSelect); this.styles = styles; @@ -190,21 +191,18 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi // Parent native select keyboard listeners - this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { + this.toDispose.push(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { this.selected = e.target.selectedIndex; this._onDidSelect.fire({ index: e.target.selectedIndex, selected: e.target.value }); - if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; - } })); // Have to implement both keyboard and mouse controllers to handle disabled options // Intercept mouse events to override normal select actions on parents - this._register(dom.addDisposableListener(this.selectElement, dom.EventType.CLICK, (e) => { + this.toDispose.push(dom.addDisposableListener(this.selectElement, dom.EventType.CLICK, (e) => { dom.EventHelper.stop(e); if (this._isVisible) { @@ -214,13 +212,13 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } })); - this._register(dom.addDisposableListener(this.selectElement, dom.EventType.MOUSE_DOWN, (e) => { + this.toDispose.push(dom.addDisposableListener(this.selectElement, dom.EventType.MOUSE_DOWN, (e) => { dom.EventHelper.stop(e); })); // Intercept keyboard handling - this._register(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { + this.toDispose.push(dom.addDisposableListener(this.selectElement, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); let showDropDown = false; @@ -290,9 +288,6 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi } this.selectElement.selectedIndex = this.selected; - if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; - } } public setAriaLabel(label: string): void { @@ -415,7 +410,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi let listBackground = this.styles.selectListBackground ? this.styles.selectListBackground.toString() : background; this.selectDropDownListContainer.style.backgroundColor = listBackground; this.selectionDetailsPane.style.backgroundColor = listBackground; - const optionsBorder = this.styles.focusBorder ? this.styles.focusBorder.toString() : ''; + const optionsBorder = this.styles.focusBorder ? this.styles.focusBorder.toString() : null; this.selectDropDownContainer.style.outlineColor = optionsBorder; this.selectDropDownContainer.style.outlineOffset = '-1px'; } @@ -749,26 +744,27 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi .filter(() => this.selectList.length > 0) .map(e => new StandardKeyboardEvent(e)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(e => this.onEnter(e), this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(e => this.onEscape(e), this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDown, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUp, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Home).on(this.onHome, this)); - this._register(onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.End).on(this.onEnd, this)); - this._register(onSelectDropDownKeyDown.filter(e => (e.keyCode >= KeyCode.KEY_0 && e.keyCode <= KeyCode.KEY_Z) || (e.keyCode >= KeyCode.US_SEMICOLON && e.keyCode <= KeyCode.NUMPAD_DIVIDE)).on(this.onCharacter, this)); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Enter).on(e => this.onEnter(e), this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Escape).on(e => this.onEscape(e), this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.UpArrow).on(this.onUpArrow, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.DownArrow).on(this.onDownArrow, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageDown).on(this.onPageDown, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.PageUp).on(this.onPageUp, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.Home).on(this.onHome, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => e.keyCode === KeyCode.End).on(this.onEnd, this, this.toDispose); + onSelectDropDownKeyDown.filter(e => (e.keyCode >= KeyCode.KEY_0 && e.keyCode <= KeyCode.KEY_Z) || (e.keyCode >= KeyCode.US_SEMICOLON && e.keyCode <= KeyCode.NUMPAD_DIVIDE)).on(this.onCharacter, this, this.toDispose); // SetUp list mouse controller - control navigation, disabled items, focus - this._register(Event.chain(domEvent(this.selectList.getHTMLElement(), 'mouseup')) + Event.chain(domEvent(this.selectList.getHTMLElement(), 'mouseup')) .filter(() => this.selectList.length > 0) - .on(e => this.onMouseUp(e), this)); + .on(e => this.onMouseUp(e), this, this.toDispose); - - this._register(this.selectList.onDidBlur(_ => this.onListBlur())); - this._register(this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index]))); - this._register(this.selectList.onFocusChange(e => this.onListFocus(e))); + this.toDispose.push( + this.selectList.onDidBlur(_ => this.onListBlur()), + this.selectList.onMouseOver(e => typeof e.index !== 'undefined' && this.selectList.setFocus([e.index])), + this.selectList.onFocusChange(e => this.onListFocus(e)) + ); this.selectList.getHTMLElement().setAttribute('aria-label', this.selectBoxOptions.ariaLabel || ''); this.selectList.getHTMLElement().setAttribute('aria-expanded', 'true'); @@ -820,11 +816,7 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi this._onDidSelect.fire({ index: this.selectElement.selectedIndex, selected: this.options[this.selected].text - }); - if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; - } } } } @@ -915,9 +907,6 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi index: this.selectElement.selectedIndex, selected: this.options[this.selected].text }); - if (!!this.options[this.selected] && !!this.options[this.selected].text) { - this.selectElement.title = this.options[this.selected].text; - } } this.hideSelectDropDown(true); @@ -1048,6 +1037,6 @@ export class SelectBoxList extends Disposable implements ISelectBoxDelegate, ILi public dispose(): void { this.hideSelectDropDown(false); - super.dispose(); + this.toDispose = dispose(this.toDispose); } } diff --git a/src/vs/base/browser/ui/selectBox/selectBoxNative.ts b/src/vs/base/browser/ui/selectBox/selectBoxNative.ts index ad588bb356..119db121fb 100644 --- a/src/vs/base/browser/ui/selectBox/selectBoxNative.ts +++ b/src/vs/base/browser/ui/selectBox/selectBoxNative.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; import * as dom from 'vs/base/browser/dom'; @@ -11,7 +11,7 @@ import * as arrays from 'vs/base/common/arrays'; import { ISelectBoxDelegate, ISelectOptionItem, ISelectBoxOptions, ISelectBoxStyles, ISelectData } from 'vs/base/browser/ui/selectBox/selectBox'; import { isMacintosh } from 'vs/base/common/platform'; -export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { +export class SelectBoxNative implements ISelectBoxDelegate { // {{SQL CARBON EDIT}} public selectElement: HTMLSelectElement; @@ -19,10 +19,11 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { private options: ISelectOptionItem[]; private selected: number; private readonly _onDidSelect: Emitter; + private toDispose: IDisposable[]; private styles: ISelectBoxStyles; constructor(options: ISelectOptionItem[], selected: number, styles: ISelectBoxStyles, selectBoxOptions?: ISelectBoxOptions) { - super(); + this.toDispose = []; this.selectBoxOptions = selectBoxOptions || Object.create(null); this.options = []; @@ -35,7 +36,8 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { this.selectElement.setAttribute('aria-label', this.selectBoxOptions.ariaLabel); } - this._onDidSelect = this._register(new Emitter()); + this._onDidSelect = new Emitter(); + this.toDispose.push(this._onDidSelect); this.styles = styles; @@ -45,7 +47,7 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { private registerListeners() { - this._register(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { + this.toDispose.push(dom.addStandardDisposableListener(this.selectElement, 'change', (e) => { this.selectElement.title = e.target.value; this._onDidSelect.fire({ index: e.target.selectedIndex, @@ -53,7 +55,7 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { }); })); - this._register(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => { + this.toDispose.push(dom.addStandardDisposableListener(this.selectElement, 'keydown', (e) => { let showSelect = false; if (isMacintosh) { @@ -167,4 +169,8 @@ export class SelectBoxNative extends Disposable implements ISelectBoxDelegate { return option; } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } } diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index 621eaff0f0..ba6bec16d7 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./panelview'; -import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; @@ -37,7 +37,7 @@ export interface IPanelStyles { * Subclasses wouldn't be able to set own properties * before the `render()` call, thus forbiding their use. */ -export abstract class Panel extends Disposable implements IView { +export abstract class Panel implements IView { private static readonly HEADER_SIZE = 22; @@ -55,9 +55,11 @@ export abstract class Panel extends Disposable implements IView { private styles: IPanelStyles = {}; private animationTimer: number | undefined = undefined; - private readonly _onDidChange = this._register(new Emitter()); + private _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; + protected disposables: IDisposable[] = []; + get draggableElement(): HTMLElement { return this.header; } @@ -112,7 +114,6 @@ export abstract class Panel extends Disposable implements IView { width: number; constructor(options: IPanelOptions = {}) { - super(); this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded; this.ariaHeaderLabel = options.ariaHeaderLabel || ''; this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120; @@ -171,26 +172,26 @@ export abstract class Panel extends Disposable implements IView { this.renderHeader(this.header); const focusTracker = trackFocus(this.header); - this._register(focusTracker); - this._register(focusTracker.onDidFocus(() => addClass(this.header, 'focused'), null)); - this._register(focusTracker.onDidBlur(() => removeClass(this.header, 'focused'), null)); + this.disposables.push(focusTracker); + focusTracker.onDidFocus(() => addClass(this.header, 'focused'), null, this.disposables); + focusTracker.onDidBlur(() => removeClass(this.header, 'focused'), null, this.disposables); this.updateHeader(); const onHeaderKeyDown = Event.chain(domEvent(this.header, 'keydown')) .map(e => new StandardKeyboardEvent(e)); - this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space) - .event(() => this.setExpanded(!this.isExpanded()), null)); + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.Enter || e.keyCode === KeyCode.Space) + .event(() => this.setExpanded(!this.isExpanded()), null, this.disposables); - this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow) - .event(() => this.setExpanded(false), null)); + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.LeftArrow) + .event(() => this.setExpanded(false), null, this.disposables); - this._register(onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow) - .event(() => this.setExpanded(true), null)); + onHeaderKeyDown.filter(e => e.keyCode === KeyCode.RightArrow) + .event(() => this.setExpanded(true), null, this.disposables); - this._register(domEvent(this.header, 'click') - (() => this.setExpanded(!this.isExpanded()), null)); + domEvent(this.header, 'click') + (() => this.setExpanded(!this.isExpanded()), null, this.disposables); this.body = append(this.element, $('.panel-body')); this.renderBody(this.body); @@ -233,6 +234,12 @@ export abstract class Panel extends Disposable implements IView { protected abstract renderHeader(container: HTMLElement): void; protected abstract renderBody(container: HTMLElement): void; protected abstract layoutBody(height: number, width: number): void; + + dispose(): void { + this.disposables = dispose(this.disposables); + + this._onDidChange.dispose(); + } } interface IDndContext { @@ -390,24 +397,24 @@ export class PanelView extends Disposable { } addPanel(panel: Panel, size: number, index = this.splitview.length): void { - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; // https://github.com/Microsoft/vscode/issues/59950 let shouldAnimate = false; - disposables.add(scheduleAtNextAnimationFrame(() => shouldAnimate = true)); + disposables.push(scheduleAtNextAnimationFrame(() => shouldAnimate = true)); - disposables.add(Event.filter(panel.onDidChange, () => shouldAnimate) - (this.setupAnimation, this)); + Event.filter(panel.onDidChange, () => shouldAnimate) + (this.setupAnimation, this, disposables); - const panelItem = { panel, disposable: disposables }; + const panelItem = { panel, disposable: combinedDisposable(disposables) }; this.panelItems.splice(index, 0, panelItem); panel.width = this.width; this.splitview.addView(panel, size, index); if (this.dnd) { const draggable = new PanelDraggable(panel, this.dnd, this.dndContext); - disposables.add(draggable); - disposables.add(draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop)); + disposables.push(draggable); + draggable.onDidDrop(this._onDidDrop.fire, this._onDidDrop, disposables); } } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index 2e0aaffd83..2f33b06bdd 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./splitview'; -import { IDisposable, toDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable, toDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as types from 'vs/base/common/types'; import * as dom from 'vs/base/browser/dom'; @@ -199,7 +199,7 @@ export class SplitView extends Disposable { const onChangeDisposable = view.onDidChange(size => this.onViewChange(item, size)); const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container)); - const disposable = combinedDisposable(onChangeDisposable, containerDisposable); + const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); const layoutContainer = this.orientation === Orientation.VERTICAL ? () => item.container.style.height = `${item.size}px` @@ -245,7 +245,7 @@ export class SplitView extends Disposable { const onEndDisposable = onEnd(this.onSashEnd, this); const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); - const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); + const disposable = combinedDisposable([onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash]); const sashItem: ISashItem = { sash, disposable }; this.sashItems.splice(index - 1, 0, sashItem); @@ -369,10 +369,10 @@ export class SplitView extends Disposable { const index = firstIndex(this.sashItems, item => item.sash === sash); // This way, we can press Alt while we resize a sash, macOS style! - const disposable = combinedDisposable( + const disposable = combinedDisposable([ domEvent(document.body, 'keydown')(e => resetSashDragState(this.sashDragState.current, e.altKey)), domEvent(document.body, 'keyup')(() => resetSashDragState(this.sashDragState.current, false)) - ); + ]); const resetSashDragState = (start: number, alt: boolean) => { const sizes = this.viewItems.map(i => i.size); diff --git a/src/vs/base/browser/ui/toolbar/toolbar.ts b/src/vs/base/browser/ui/toolbar/toolbar.ts index 1c5d0b888f..7d08f03117 100644 --- a/src/vs/base/browser/ui/toolbar/toolbar.ts +++ b/src/vs/base/browser/ui/toolbar/toolbar.ts @@ -114,7 +114,7 @@ export class ToolBar extends Disposable { this.actionBar.setAriaLabel(label); } - setActions(primaryActions: ReadonlyArray, secondaryActions?: ReadonlyArray): () => void { + setActions(primaryActions: IAction[], secondaryActions?: IAction[]): () => void { return () => { let primaryActionsToSet = primaryActions ? primaryActions.slice(0) : []; @@ -169,7 +169,7 @@ class ToggleMenuAction extends Action { static readonly ID = 'toolbar.toggle.more'; - private _menuActions: ReadonlyArray; + private _menuActions: IAction[]; private toggleDropdownMenu: () => void; constructor(toggleDropdownMenu: () => void, title?: string) { @@ -185,11 +185,11 @@ class ToggleMenuAction extends Action { return Promise.resolve(true); } - get menuActions(): ReadonlyArray { + get menuActions() { return this._menuActions; } - set menuActions(actions: ReadonlyArray) { + set menuActions(actions: IAction[]) { this._menuActions = actions; } } \ No newline at end of file diff --git a/src/vs/base/common/actions.ts b/src/vs/base/common/actions.ts index c4bd897e36..8a75a27d5c 100644 --- a/src/vs/base/common/actions.ts +++ b/src/vs/base/common/actions.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; export interface ITelemetryData { @@ -29,13 +29,14 @@ export interface IActionRunner extends IDisposable { onDidBeforeRun: Event; } -export interface IActionViewItem extends IDisposable { +export interface IActionViewItem { actionRunner: IActionRunner; setActionContext(context: any): void; render(element: any /* HTMLElement */): void; isEnabled(): boolean; focus(): void; blur(): void; + dispose(): void; } export interface IActionChangeEvent { @@ -47,9 +48,9 @@ export interface IActionChangeEvent { radio?: boolean; } -export class Action extends Disposable implements IAction { +export class Action implements IAction { - protected _onDidChange = this._register(new Emitter()); + protected _onDidChange = new Emitter(); readonly onDidChange: Event = this._onDidChange.event; protected _id: string; @@ -62,7 +63,6 @@ export class Action extends Disposable implements IAction { protected _actionCallback?: (event?: any) => Promise; constructor(id: string, label: string = '', cssClass: string = '', enabled: boolean = true, actionCallback?: (event?: any) => Promise) { - super(); this._id = id; this._label = label; this._cssClass = cssClass; @@ -171,6 +171,10 @@ export class Action extends Disposable implements IAction { return Promise.resolve(true); } + + dispose() { + this._onDidChange.dispose(); + } } export interface IRunEvent { @@ -213,8 +217,8 @@ export class RadioGroup extends Disposable { constructor(readonly actions: Action[]) { super(); - for (const action of actions) { - this._register(action.onDidChange(e => { + this._register(combinedDisposable(actions.map(action => { + return action.onDidChange(e => { if (e.checked && action.checked) { for (const candidate of actions) { if (candidate !== action) { @@ -222,7 +226,7 @@ export class RadioGroup extends Disposable { } } } - })); - } + }); + }))); } } diff --git a/src/vs/base/common/async.ts b/src/vs/base/common/async.ts index 131df405be..27dde86362 100644 --- a/src/vs/base/common/async.ts +++ b/src/vs/base/common/async.ts @@ -6,7 +6,7 @@ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as errors from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; export function isThenable(obj: any): obj is Promise { @@ -415,11 +415,11 @@ export class Limiter { this._onFinished = new Emitter(); } - get onFinished(): Event { + public get onFinished(): Event { return this._onFinished.event; } - get size(): number { + public get size(): number { return this._size; // return this.runningPromises + this.outstandingPromises.length; } @@ -455,7 +455,7 @@ export class Limiter { } } - dispose(): void { + public dispose(): void { this._onFinished.dispose(); } } @@ -475,30 +475,35 @@ export class Queue extends Limiter { * by disposing them once the queue is empty. */ export class ResourceQueue { - private queues: Map> = new Map(); + private queues: { [path: string]: Queue }; - queueFor(resource: URI): Queue { + constructor() { + this.queues = Object.create(null); + } + + public queueFor(resource: URI): Queue { const key = resource.toString(); - if (!this.queues.has(key)) { + if (!this.queues[key]) { const queue = new Queue(); queue.onFinished(() => { queue.dispose(); - this.queues.delete(key); + delete this.queues[key]; }); - this.queues.set(key, queue); + this.queues[key] = queue; } - return this.queues.get(key)!; + return this.queues[key]; } } -export class TimeoutTimer implements IDisposable { +export class TimeoutTimer extends Disposable { private _token: any; constructor(); constructor(runner: () => void, timeout: number); constructor(runner?: () => void, timeout?: number) { + super(); this._token = -1; if (typeof runner === 'function' && typeof timeout === 'number') { @@ -508,6 +513,7 @@ export class TimeoutTimer implements IDisposable { dispose(): void { this.cancel(); + super.dispose(); } cancel(): void { @@ -537,16 +543,18 @@ export class TimeoutTimer implements IDisposable { } } -export class IntervalTimer implements IDisposable { +export class IntervalTimer extends Disposable { private _token: any; constructor() { + super(); this._token = -1; } dispose(): void { this.cancel(); + super.dispose(); } cancel(): void { diff --git a/src/vs/base/common/cache.ts b/src/vs/base/common/cache.ts index bb43d54730..74ef0199ff 100644 --- a/src/vs/base/common/cache.ts +++ b/src/vs/base/common/cache.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; -import { IDisposable } from 'vs/base/common/lifecycle'; -export interface CacheResult extends IDisposable { +export interface CacheResult { promise: Promise; + dispose(): void; } export class Cache { diff --git a/src/vs/base/common/errorsWithActions.ts b/src/vs/base/common/errorsWithActions.ts index 86a4d5c6ac..e69f58757d 100644 --- a/src/vs/base/common/errorsWithActions.ts +++ b/src/vs/base/common/errorsWithActions.ts @@ -6,11 +6,11 @@ import { IAction } from 'vs/base/common/actions'; export interface IErrorOptions { - actions?: ReadonlyArray; + actions?: IAction[]; } export interface IErrorWithActions { - actions?: ReadonlyArray; + actions?: IAction[]; } export function isErrorWithActions(obj: any): obj is IErrorWithActions { diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 2e3b1f5459..c34b499e89 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -5,7 +5,7 @@ import { onUnexpectedError } from 'vs/base/common/errors'; import { once as onceFn } from 'vs/base/common/functional'; -import { Disposable, IDisposable, toDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { LinkedList } from 'vs/base/common/linkedList'; /** @@ -13,11 +13,12 @@ import { LinkedList } from 'vs/base/common/linkedList'; * can be subscribed. The event is the subscriber function itself. */ export interface Event { - (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore): IDisposable; + (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]): IDisposable; } export namespace Event { - export const None: Event = () => Disposable.None; + const _disposable = { dispose() { } }; + export const None: Event = function () { return _disposable; }; /** * Given an event, returns another event which only fires once. @@ -85,7 +86,7 @@ export namespace Event { * whenever any of the provided events emit. */ export function any(...events: Event[]): Event { - return (listener, thisArgs = null, disposables?) => combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); + return (listener, thisArgs = null, disposables?) => combinedDisposable(events.map(event => event(e => listener.call(thisArgs, e), null, disposables))); } /** @@ -476,7 +477,7 @@ export class Emitter { */ get event(): Event { if (!this._event) { - this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[] | DisposableStore) => { + this._event = (listener: (e: T) => any, thisArgs?: any, disposables?: IDisposable[]) => { if (!this._listeners) { this._listeners = new LinkedList(); } @@ -521,9 +522,7 @@ export class Emitter { } } }; - if (disposables instanceof DisposableStore) { - disposables.add(result); - } else if (Array.isArray(disposables)) { + if (Array.isArray(disposables)) { disposables.push(result); } diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 1ee7e3331c..6b23264127 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -458,14 +458,14 @@ export function parse(arg1: string | IExpression | IRelativePattern, options: IG if (parsedPattern === NULL) { return FALSE; } - const resultPattern: ParsedPattern & { allBasenames?: string[]; allPaths?: string[]; } = function (path: string, basename: string) { + const resultPattern = function (path: string, basename: string) { return !!parsedPattern(path, basename); }; if (parsedPattern.allBasenames) { - resultPattern.allBasenames = parsedPattern.allBasenames; + (resultPattern).allBasenames = parsedPattern.allBasenames; } if (parsedPattern.allPaths) { - resultPattern.allPaths = parsedPattern.allPaths; + (resultPattern).allPaths = parsedPattern.allPaths; } return resultPattern; } diff --git a/src/vs/base/common/lifecycle.ts b/src/vs/base/common/lifecycle.ts index 984c36aaaa..178e9c0ee3 100644 --- a/src/vs/base/common/lifecycle.ts +++ b/src/vs/base/common/lifecycle.ts @@ -5,44 +5,6 @@ import { once } from 'vs/base/common/functional'; -/** - * Enables logging of potentially leaked disposables. - * - * A disposable is considered leaked if it is not disposed or not registered as the child of - * another disposable. This tracking is very simple an only works for classes that either - * extend Disposable or use a DisposableStore. This means there are a lot of false positives. - */ -const TRACK_DISPOSABLES = false; - -const __is_disposable_tracked__ = '__is_disposable_tracked__'; - -function markTracked(x: T): void { - if (!TRACK_DISPOSABLES) { - return; - } - - if (x && x !== Disposable.None) { - try { - x[__is_disposable_tracked__] = true; - } catch { - // noop - } - } -} - -function trackDisposable(x: T): void { - if (!TRACK_DISPOSABLES) { - return; - } - - const stack = new Error().stack!; - setTimeout(() => { - if (!x[__is_disposable_tracked__]) { - console.log(stack); - } - }, 3000); -} - export interface IDisposable { dispose(): void; } @@ -53,94 +15,56 @@ export function isDisposable(thing: E): thing is E & IDisposab } export function dispose(disposable: T): T; -export function dispose(disposable: T | undefined): T | undefined; -export function dispose(disposables: Array): Array; -export function dispose(disposables: ReadonlyArray): ReadonlyArray; -export function dispose(disposables: T | T[] | undefined): T | T[] | undefined { - if (Array.isArray(disposables)) { - disposables.forEach(d => { - if (d) { - markTracked(d); - d.dispose(); - } - }); +export function dispose(...disposables: Array): T[]; +export function dispose(disposables: T[]): T[]; +export function dispose(first: T | T[], ...rest: T[]): T | T[] | undefined { + if (Array.isArray(first)) { + first.forEach(d => d && d.dispose()); return []; - } else if (disposables) { - markTracked(disposables); - disposables.dispose(); - return disposables; - } else { + } else if (rest.length === 0) { + if (first) { + first.dispose(); + return first; + } return undefined; + } else { + dispose(first); + dispose(rest); + return []; } } -export function combinedDisposable(...disposables: IDisposable[]): IDisposable { - disposables.forEach(markTracked); +export function combinedDisposable(disposables: IDisposable[]): IDisposable { return { dispose: () => dispose(disposables) }; } export function toDisposable(fn: () => void): IDisposable { - return { dispose: fn }; -} - -export class DisposableStore implements IDisposable { - private _toDispose = new Set(); - private _isDisposed = false; - - /** - * Dispose of all registered disposables and mark this object as disposed. - * - * Any future disposables added to this object will be disposed of on `add`. - */ - public dispose(): void { - markTracked(this); - this._isDisposed = true; - this.clear(); - } - - /** - * Dispose of all registered disposables but do not mark this object as disposed. - */ - public clear(): void { - this._toDispose.forEach(item => item.dispose()); - this._toDispose.clear(); - } - - public add(t: T): T { - if (!t) { - return t; - } - - markTracked(t); - if (this._isDisposed) { - console.warn(new Error('Registering disposable on object that has already been disposed of').stack); - t.dispose(); - } else { - this._toDispose.add(t); - } - - return t; - } + return { dispose() { fn(); } }; } export abstract class Disposable implements IDisposable { static None = Object.freeze({ dispose() { } }); - private readonly _store = new DisposableStore(); + protected _toDispose: IDisposable[] = []; + protected get toDispose(): IDisposable[] { return this._toDispose; } - constructor() { - trackDisposable(this); - } + private _lifecycle_disposable_isDisposed = false; public dispose(): void { - markTracked(this); - - this._store.dispose(); + this._lifecycle_disposable_isDisposed = true; + this._toDispose = dispose(this._toDispose); } protected _register(t: T): T { - return this._store.add(t); + if (this._lifecycle_disposable_isDisposed) { + console.warn('Registering disposable on object that has already been disposed.'); + t.dispose(); + } else { + this._toDispose.push(t); + } + + return t; } } @@ -150,23 +74,22 @@ export interface IReference extends IDisposable { export abstract class ReferenceCollection { - private references: Map = new Map(); + private references: { [key: string]: { readonly object: T; counter: number; } } = Object.create(null); constructor() { } acquire(key: string): IReference { - let reference = this.references.get(key); + let reference = this.references[key]; if (!reference) { - reference = { counter: 0, object: this.createReferencedObject(key) }; - this.references.set(key, reference); + reference = this.references[key] = { counter: 0, object: this.createReferencedObject(key) }; } const { object } = reference; const dispose = once(() => { - if (--reference!.counter === 0) { - this.destroyReferencedObject(key, reference!.object); - this.references.delete(key); + if (--reference.counter === 0) { + this.destroyReferencedObject(key, reference.object); + delete this.references[key]; } }); diff --git a/src/vs/base/common/uri.ts b/src/vs/base/common/uri.ts index 84e014a487..f2501bf249 100644 --- a/src/vs/base/common/uri.ts +++ b/src/vs/base/common/uri.ts @@ -96,16 +96,6 @@ const _empty = ''; const _slash = '/'; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; -function _isQueryStringScheme(scheme: string) { - switch (scheme.toLowerCase()) { - case 'http': - case 'https': - case 'ftp': - return true; - } - return false; -} - /** * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. * This class is a simple parser which creates the basic component parts @@ -292,14 +282,14 @@ export class URI implements UriComponents { static parse(value: string, _strict: boolean = false): URI { const match = _regexp.exec(value); if (!match) { - return new _URI(_empty, _empty, _empty, _empty, _empty, _strict); + return new _URI(_empty, _empty, _empty, _empty, _empty); } return new _URI( match[2] || _empty, - decodeURIComponentFast(match[4] || _empty, false, false), - decodeURIComponentFast(match[5] || _empty, true, false), - decodeURIComponentFast(match[7] || _empty, false, _isQueryStringScheme(match[2])), - decodeURIComponentFast(match[9] || _empty, false, false), + decodeURIComponent(match[4] || _empty), + decodeURIComponent(match[5] || _empty), + decodeURIComponent(match[7] || _empty), + decodeURIComponent(match[9] || _empty), _strict ); } @@ -331,7 +321,7 @@ export class URI implements UriComponents { // normalize to fwd-slashes on windows, // on other systems bwd-slashes are valid - // filename character, e.g. /f\oo/ba\r.txt + // filename character, eg /f\oo/ba\r.txt if (isWindows) { path = path.replace(/\\/g, _slash); } @@ -395,8 +385,8 @@ export class URI implements UriComponents { return data; } else { const result = new _URI(data); + result._fsPath = (data).fsPath; result._formatted = (data).external; - result._fsPath = (data)._sep === _pathSepMarker ? (data).fsPath : null; return result; } } @@ -412,12 +402,10 @@ export interface UriComponents { interface UriState extends UriComponents { $mid: number; - external: string; fsPath: string; - _sep: 1 | undefined; + external: string; } -const _pathSepMarker = isWindows ? 1 : undefined; // tslint:disable-next-line:class-name class _URI extends URI { @@ -451,7 +439,6 @@ class _URI extends URI { // cached state if (this._fsPath) { res.fsPath = this._fsPath; - res._sep = _pathSepMarker; } if (this._formatted) { res.external = this._formatted; @@ -476,84 +463,6 @@ class _URI extends URI { } } -function isHex(value: string, pos: number): boolean { - if (pos >= value.length) { - return false; - } - const code = value.charCodeAt(pos); - return (code >= CharCode.Digit0 && code <= CharCode.Digit9)// 0-9 - || (code >= CharCode.a && code <= CharCode.f) //a-f - || (code >= CharCode.A && code <= CharCode.F); //A-F -} - - -function decodeURIComponentFast(uriComponent: string, isPath: boolean, isQueryString: boolean): string { - - let res: string | undefined; - let nativeDecodePos = -1; - - for (let pos = 0; pos < uriComponent.length; pos++) { - const code = uriComponent.charCodeAt(pos); - - // decoding needed - if (code === CharCode.PercentSign && isHex(uriComponent, pos + 1) && isHex(uriComponent, pos + 2)) { - - const chA = uriComponent.charCodeAt(pos + 1); - const chB = uriComponent.charCodeAt(pos + 2); - - // when in a path -> check and accept %2f and %2F (fwd slash) - // when in a query string -> check and accept %3D, %26, and %3B (equals, ampersand, semi-colon) - if ( - (isPath && chA === CharCode.Digit2 && (chB === CharCode.F || chB === CharCode.f)) - || - (isQueryString && ( - (chA === CharCode.Digit2 && chB === CharCode.Digit6) // %26 - || - (chA === CharCode.Digit3 && (chB === CharCode.B || chB === CharCode.b || chB === CharCode.D || chB === CharCode.d)) // %3D, %3D - )) - ) { - if (nativeDecodePos !== -1) { - res += decodeURIComponent(uriComponent.substring(nativeDecodePos, pos)); - nativeDecodePos = -1; - } - - if (res !== undefined) { - res += uriComponent.substr(pos, 3); - } - - pos += 2; - continue; - } - - if (res === undefined) { - res = uriComponent.substring(0, pos); - } - if (nativeDecodePos === -1) { - nativeDecodePos = pos; - } - - pos += 2; - - } else { - - if (nativeDecodePos !== -1) { - res += decodeURIComponent(uriComponent.substring(nativeDecodePos, pos)); - nativeDecodePos = -1; - } - - if (res !== undefined) { - res += String.fromCharCode(code); - } - } - } - - if (nativeDecodePos !== -1) { - res += decodeURIComponent(uriComponent.substr(nativeDecodePos)); - } - - return res !== undefined ? res : uriComponent; -} - // reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2 const encodeTable: { [ch: number]: string } = { [CharCode.Colon]: '%3A', // gen-delims @@ -579,7 +488,7 @@ const encodeTable: { [ch: number]: string } = { [CharCode.Space]: '%20', }; -function encodeURIComponentFast(uriComponent: string, isPath: boolean, isQueryString: boolean): string { +function encodeURIComponentFast(uriComponent: string, allowSlash: boolean): string { let res: string | undefined = undefined; let nativeEncodePos = -1; @@ -595,8 +504,7 @@ function encodeURIComponentFast(uriComponent: string, isPath: boolean, isQuerySt || code === CharCode.Period || code === CharCode.Underline || code === CharCode.Tilde - || (isPath && code === CharCode.Slash) // path => allow slash AS-IS - || (isQueryString && (code === CharCode.Equals || code === CharCode.Ampersand || code === CharCode.Semicolon)) // query string => allow &=; + || (allowSlash && code === CharCode.Slash) ) { // check if we are delaying native encode if (nativeEncodePos !== -1) { @@ -608,20 +516,6 @@ function encodeURIComponentFast(uriComponent: string, isPath: boolean, isQuerySt res += uriComponent.charAt(pos); } - } else if (code === CharCode.PercentSign && isHex(uriComponent, pos + 1) && isHex(uriComponent, pos + 2)) { - // at percentage encoded value - - // check if we are delaying native encode - if (nativeEncodePos !== -1) { - res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos)); - nativeEncodePos = -1; - } - // check if we write into a new string (by default we try to return the param) - if (res !== undefined) { - res += uriComponent.substr(pos, 3); - } - pos += 2; - } else { // encoding needed, we need to allocate a new string if (res === undefined) { @@ -710,7 +604,6 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { let res = ''; let { scheme, authority, path, query, fragment } = uri; - if (scheme) { res += scheme; res += ':'; @@ -727,22 +620,22 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { authority = authority.substr(idx + 1); idx = userinfo.indexOf(':'); if (idx === -1) { - res += encoder(userinfo, false, false); + res += encoder(userinfo, false); } else { // :@ - res += encoder(userinfo.substr(0, idx), false, false); + res += encoder(userinfo.substr(0, idx), false); res += ':'; - res += encoder(userinfo.substr(idx + 1), false, false); + res += encoder(userinfo.substr(idx + 1), false); } res += '@'; } authority = authority.toLowerCase(); idx = authority.indexOf(':'); if (idx === -1) { - res += encoder(authority, false, false); + res += encoder(authority, false); } else { // : - res += encoder(authority.substr(0, idx), false, false); + res += encoder(authority.substr(0, idx), false); res += authority.substr(idx); } } @@ -760,15 +653,15 @@ function _asFormatted(uri: URI, skipEncoding: boolean): string { } } // encode the rest of the path - res += encoder(path, true, false); + res += encoder(path, true); } if (query) { res += '?'; - res += encoder(query, false, _isQueryStringScheme(scheme)); + res += encoder(query, false); } if (fragment) { res += '#'; - res += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment; + res += !skipEncoding ? encodeURIComponentFast(fragment, false) : fragment; } return res; } diff --git a/src/vs/base/common/uriIpc.ts b/src/vs/base/common/uriIpc.ts index 7cfc81703b..96fe079105 100644 --- a/src/vs/base/common/uriIpc.ts +++ b/src/vs/base/common/uriIpc.ts @@ -10,51 +10,6 @@ export interface IURITransformer { transformIncoming(uri: UriComponents): UriComponents; transformOutgoing(uri: UriComponents): UriComponents; transformOutgoingURI(uri: URI): URI; - transformOutgoingScheme(scheme: string): string; -} - -export interface UriParts { - scheme: string; - authority?: string; - path?: string; -} - -export interface IRawURITransformer { - transformIncoming(uri: UriParts): UriParts; - transformOutgoing(uri: UriParts): UriParts; - transformOutgoingScheme(scheme: string): string; -} - -function toJSON(uri: URI): UriComponents { - return uri.toJSON(); -} - -export class URITransformer implements IURITransformer { - - private readonly _uriTransformer: IRawURITransformer; - - constructor(uriTransformer: IRawURITransformer) { - this._uriTransformer = uriTransformer; - } - - public transformIncoming(uri: UriComponents): UriComponents { - const result = this._uriTransformer.transformIncoming(uri); - return (result === uri ? uri : toJSON(URI.from(result))); - } - - public transformOutgoing(uri: UriComponents): UriComponents { - const result = this._uriTransformer.transformOutgoing(uri); - return (result === uri ? uri : toJSON(URI.from(result))); - } - - public transformOutgoingURI(uri: URI): URI { - const result = this._uriTransformer.transformOutgoing(uri); - return (result === uri ? uri : URI.from(result)); - } - - public transformOutgoingScheme(scheme: string): string { - return this._uriTransformer.transformOutgoingScheme(scheme); - } } export const DefaultURITransformer: IURITransformer = new class { @@ -69,10 +24,6 @@ export const DefaultURITransformer: IURITransformer = new class { transformOutgoingURI(uri: URI): URI { return uri; } - - transformOutgoingScheme(scheme: string): string { - return scheme; - } }; function _transformOutgoingURIs(obj: any, transformer: IURITransformer, depth: number): any { diff --git a/src/vs/base/common/worker/simpleWorker.ts b/src/vs/base/common/worker/simpleWorker.ts index 31a402286f..1655a685ed 100644 --- a/src/vs/base/common/worker/simpleWorker.ts +++ b/src/vs/base/common/worker/simpleWorker.ts @@ -4,15 +4,16 @@ *--------------------------------------------------------------------------------------------*/ import { transformErrorForSerialization } from 'vs/base/common/errors'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { isWeb } from 'vs/base/common/platform'; import { getAllPropertyNames } from 'vs/base/common/types'; const INITIALIZE = '$initialize'; -export interface IWorker extends IDisposable { +export interface IWorker { getId(): number; postMessage(message: string): void; + dispose(): void; } export interface IWorkerCallback { diff --git a/src/vs/base/node/config.ts b/src/vs/base/node/config.ts index 1f861e37de..8ad630fc4f 100644 --- a/src/vs/base/node/config.ts +++ b/src/vs/base/node/config.ts @@ -6,7 +6,7 @@ import * as fs from 'fs'; import { dirname } from 'vs/base/common/path'; import * as objects from 'vs/base/common/objects'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as json from 'vs/base/common/json'; import { statLink } from 'vs/base/node/pfs'; @@ -41,17 +41,20 @@ export interface IConfigOptions { * - delayed processing of changes to accomodate for lots of changes * - configurable defaults */ -export class ConfigWatcher extends Disposable implements IConfigWatcher { +export class ConfigWatcher implements IConfigWatcher, IDisposable { private cache: T; private parseErrors: json.ParseError[]; private disposed: boolean; private loaded: boolean; private timeoutHandle: NodeJS.Timer | null; + private disposables: IDisposable[]; private readonly _onDidUpdateConfiguration: Emitter>; constructor(private _path: string, private options: IConfigOptions = { defaultConfig: Object.create(null), onError: error => console.error(error) }) { - super(); - this._onDidUpdateConfiguration = this._register(new Emitter>()); + this.disposables = []; + + this._onDidUpdateConfiguration = new Emitter>(); + this.disposables.push(this._onDidUpdateConfiguration); this.registerWatcher(); this.initAsync(); @@ -108,10 +111,10 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { try { this.parseErrors = []; res = this.options.parse ? this.options.parse(raw, this.parseErrors) : json.parse(raw, this.parseErrors); - return res || this.options.defaultConfig; } catch (error) { - return this.options.defaultConfig; // Ignore parsing errors + // Ignore parsing errors + return this.options.defaultConfig; } } @@ -122,7 +125,7 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { this.watch(parentFolder, true); // Check if the path is a symlink and watch its target if so - this.handleSymbolicLink().then(undefined, () => { /* ignore error */ }); + this.handleSymbolicLink().then(undefined, error => { /* ignore error */ }); } private async handleSymbolicLink(): Promise { @@ -140,9 +143,9 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { } if (isFolder) { - this._register(watchFolder(path, (type, path) => path === this._path ? this.onConfigFileChange() : undefined, error => this.options.onError(error))); + this.disposables.push(watchFolder(path, (type, path) => path === this._path ? this.onConfigFileChange() : undefined, error => this.options.onError(error))); } else { - this._register(watchFile(path, () => this.onConfigFileChange(), error => this.options.onError(error))); + this.disposables.push(watchFile(path, (type, path) => this.onConfigFileChange(), error => this.options.onError(error))); } } @@ -184,6 +187,6 @@ export class ConfigWatcher extends Disposable implements IConfigWatcher { dispose(): void { this.disposed = true; - super.dispose(); + this.disposables = dispose(this.disposables); } } \ No newline at end of file diff --git a/src/vs/base/node/pfs.ts b/src/vs/base/node/pfs.ts index 9313a89adb..a4c4af6635 100644 --- a/src/vs/base/node/pfs.ts +++ b/src/vs/base/node/pfs.ts @@ -226,7 +226,7 @@ export function readFile(path: string, encoding?: string): Promise> = new Map(); +const writeFilePathQueue: { [path: string]: Queue } = Object.create(null); export function writeFile(path: string, data: string, options?: IWriteFileOptions): Promise; export function writeFile(path: string, data: Buffer, options?: IWriteFileOptions): Promise; @@ -249,20 +249,18 @@ function toQueueKey(path: string): string { } function ensureWriteFileQueue(queueKey: string): Queue { - const existingWriteFileQueue = writeFilePathQueues.get(queueKey); - if (existingWriteFileQueue) { - return existingWriteFileQueue; + let writeFileQueue = writeFilePathQueue[queueKey]; + if (!writeFileQueue) { + writeFileQueue = new Queue(); + writeFilePathQueue[queueKey] = writeFileQueue; + + const onFinish = Event.once(writeFileQueue.onFinished); + onFinish(() => { + delete writeFilePathQueue[queueKey]; + writeFileQueue.dispose(); + }); } - const writeFileQueue = new Queue(); - writeFilePathQueues.set(queueKey, writeFileQueue); - - const onFinish = Event.once(writeFileQueue.onFinished); - onFinish(() => { - writeFilePathQueues.delete(queueKey); - writeFileQueue.dispose(); - }); - return writeFileQueue; } diff --git a/src/vs/base/node/processes.ts b/src/vs/base/node/processes.ts index fa93ee0f00..a98bcc4de4 100644 --- a/src/vs/base/node/processes.ts +++ b/src/vs/base/node/processes.ts @@ -5,7 +5,6 @@ import * as path from 'vs/base/common/path'; import * as fs from 'fs'; -import { promisify } from 'util'; import * as cp from 'child_process'; import * as nls from 'vs/nls'; import * as Types from 'vs/base/common/types'; @@ -405,7 +404,7 @@ export function createQueuedSender(childProcess: cp.ChildProcess): IQueuedSender } export namespace win32 { - export async function findExecutable(command: string, cwd?: string, paths?: string[]): Promise { + export function findExecutable(command: string, cwd?: string, paths?: string[]): string { // If we have an absolute path then we take it. if (path.isAbsolute(command)) { return command; @@ -436,15 +435,15 @@ export namespace win32 { } else { fullPath = path.join(cwd, pathEntry, command); } - if (await promisify(fs.exists)(fullPath)) { + if (fs.existsSync(fullPath)) { return fullPath; } let withExtension = fullPath + '.com'; - if (await promisify(fs.exists)(withExtension)) { + if (fs.existsSync(withExtension)) { return withExtension; } withExtension = fullPath + '.exe'; - if (await promisify(fs.exists)(withExtension)) { + if (fs.existsSync(withExtension)) { return withExtension; } } diff --git a/src/vs/base/parts/ipc/common/ipc.net.ts b/src/vs/base/parts/ipc/common/ipc.net.ts index 5ec8df2f7c..4148a623b4 100644 --- a/src/vs/base/parts/ipc/common/ipc.net.ts +++ b/src/vs/base/parts/ipc/common/ipc.net.ts @@ -11,12 +11,13 @@ import * as platform from 'vs/base/common/platform'; declare var process: any; -export interface ISocket extends IDisposable { +export interface ISocket { onData(listener: (e: VSBuffer) => void): IDisposable; onClose(listener: () => void): IDisposable; onEnd(listener: () => void): IDisposable; write(buffer: VSBuffer): void; end(): void; + dispose(): void; } let emptyBuffer: VSBuffer | null = null; @@ -406,7 +407,7 @@ export class Client extends IPCClient { /** * Will ensure no messages are lost if there are no event listeners. */ -export function createBufferedEvent(source: Event): Event { +function createBufferedEvent(source: Event): Event { let emitter: Emitter; let hasListeners = false; let isDeliveringMessages = false; @@ -513,7 +514,7 @@ class Queue { * Same as Protocol, but will actually track messages and acks. * Moreover, it will ensure no messages are lost if there are no event listeners. */ -export class PersistentProtocol implements IMessagePassingProtocol { +export class PersistentProtocol { private _isReconnecting: boolean; diff --git a/src/vs/base/parts/ipc/common/ipc.ts b/src/vs/base/parts/ipc/common/ipc.ts index 29b8a47954..adc9cfbf31 100644 --- a/src/vs/base/parts/ipc/common/ipc.ts +++ b/src/vs/base/parts/ipc/common/ipc.ts @@ -464,7 +464,7 @@ export class ChannelClient implements IChannelClient, IDisposable { }; const cancellationTokenListener = cancellationToken.onCancellationRequested(cancel); - disposable = combinedDisposable(toDisposable(cancel), cancellationTokenListener); + disposable = combinedDisposable([toDisposable(cancel), cancellationTokenListener]); this.activeRequests.add(disposable); }); diff --git a/src/vs/base/parts/ipc/node/ipc.net.ts b/src/vs/base/parts/ipc/node/ipc.net.ts index 5a79572f41..5a9b6f76d4 100644 --- a/src/vs/base/parts/ipc/node/ipc.net.ts +++ b/src/vs/base/parts/ipc/node/ipc.net.ts @@ -4,14 +4,14 @@ *--------------------------------------------------------------------------------------------*/ import { Socket, Server as NetServer, createConnection, createServer } from 'net'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { ClientConnectionEvent, IPCServer } from 'vs/base/parts/ipc/common/ipc'; import { join } from 'vs/base/common/path'; import { tmpdir } from 'os'; import { generateUuid } from 'vs/base/common/uuid'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { VSBuffer } from 'vs/base/common/buffer'; -import { ISocket, Protocol, Client, ChunkStream } from 'vs/base/parts/ipc/common/ipc.net'; +import { ISocket, Protocol, Client } from 'vs/base/parts/ipc/common/ipc.net'; export class NodeSocket implements ISocket { public readonly socket: Socket; @@ -65,197 +65,6 @@ export class NodeSocket implements ISocket { } } -const enum Constants { - MinHeaderByteSize = 2 -} - -const enum ReadState { - PeekHeader = 1, - ReadHeader = 2, - ReadBody = 3, - Fin = 4 -} - -/** - * See https://tools.ietf.org/html/rfc6455#section-5.2 - */ -export class WebSocketNodeSocket extends Disposable implements ISocket { - - public readonly socket: NodeSocket; - private readonly _incomingData: ChunkStream; - private readonly _onData = this._register(new Emitter()); - - private readonly _state = { - state: ReadState.PeekHeader, - readLen: Constants.MinHeaderByteSize, - mask: 0 - }; - - constructor(socket: NodeSocket) { - super(); - this.socket = socket; - this._incomingData = new ChunkStream(); - this._register(this.socket.onData(data => this._acceptChunk(data))); - } - - public dispose(): void { - this.socket.dispose(); - } - - public onData(listener: (e: VSBuffer) => void): IDisposable { - return this._onData.event(listener); - } - - public onClose(listener: () => void): IDisposable { - return this.socket.onClose(listener); - } - - public onEnd(listener: () => void): IDisposable { - return this.socket.onEnd(listener); - } - - public write(buffer: VSBuffer): void { - let headerLen = Constants.MinHeaderByteSize; - if (buffer.byteLength < 126) { - headerLen += 0; - } else if (buffer.byteLength < 2 ** 16) { - headerLen += 2; - } else { - headerLen += 8; - } - const header = VSBuffer.alloc(headerLen); - - header.writeUInt8(0b10000010, 0); - if (buffer.byteLength < 126) { - header.writeUInt8(buffer.byteLength, 1); - } else if (buffer.byteLength < 2 ** 16) { - header.writeUInt8(126, 1); - let offset = 1; - header.writeUInt8((buffer.byteLength >>> 8) & 0b11111111, ++offset); - header.writeUInt8((buffer.byteLength >>> 0) & 0b11111111, ++offset); - } else { - header.writeUInt8(127, 1); - let offset = 1; - header.writeUInt8(0, ++offset); - header.writeUInt8(0, ++offset); - header.writeUInt8(0, ++offset); - header.writeUInt8(0, ++offset); - header.writeUInt8((buffer.byteLength >>> 24) & 0b11111111, ++offset); - header.writeUInt8((buffer.byteLength >>> 16) & 0b11111111, ++offset); - header.writeUInt8((buffer.byteLength >>> 8) & 0b11111111, ++offset); - header.writeUInt8((buffer.byteLength >>> 0) & 0b11111111, ++offset); - } - - this.socket.write(VSBuffer.concat([header, buffer])); - } - - public end(): void { - this.socket.end(); - } - - private _acceptChunk(data: VSBuffer): void { - if (data.byteLength === 0) { - return; - } - - this._incomingData.acceptChunk(data); - - while (this._incomingData.byteLength >= this._state.readLen) { - - if (this._state.state === ReadState.PeekHeader) { - // peek to see if we can read the entire header - const peekHeader = this._incomingData.peek(this._state.readLen); - // const firstByte = peekHeader.readUInt8(0); - // const finBit = (firstByte & 0b10000000) >>> 7; - const secondByte = peekHeader.readUInt8(1); - const hasMask = (secondByte & 0b10000000) >>> 7; - const len = (secondByte & 0b01111111); - - this._state.state = ReadState.ReadHeader; - this._state.readLen = Constants.MinHeaderByteSize + (hasMask ? 4 : 0) + (len === 126 ? 2 : 0) + (len === 127 ? 8 : 0); - this._state.mask = 0; - - } else if (this._state.state === ReadState.ReadHeader) { - // read entire header - const header = this._incomingData.read(this._state.readLen); - const secondByte = header.readUInt8(1); - const hasMask = (secondByte & 0b10000000) >>> 7; - let len = (secondByte & 0b01111111); - - let offset = 1; - if (len === 126) { - len = ( - header.readUInt8(++offset) * 2 ** 8 - + header.readUInt8(++offset) - ); - } else if (len === 127) { - len = ( - header.readUInt8(++offset) * 0 - + header.readUInt8(++offset) * 0 - + header.readUInt8(++offset) * 0 - + header.readUInt8(++offset) * 0 - + header.readUInt8(++offset) * 2 ** 24 - + header.readUInt8(++offset) * 2 ** 16 - + header.readUInt8(++offset) * 2 ** 8 - + header.readUInt8(++offset) - ); - } - - let mask = 0; - if (hasMask) { - mask = ( - header.readUInt8(++offset) * 2 ** 24 - + header.readUInt8(++offset) * 2 ** 16 - + header.readUInt8(++offset) * 2 ** 8 - + header.readUInt8(++offset) - ); - } - - this._state.state = ReadState.ReadBody; - this._state.readLen = len; - this._state.mask = mask; - - } else if (this._state.state === ReadState.ReadBody) { - // read body - - const body = this._incomingData.read(this._state.readLen); - unmask(body, this._state.mask); - - this._state.state = ReadState.PeekHeader; - this._state.readLen = Constants.MinHeaderByteSize; - this._state.mask = 0; - - this._onData.fire(body); - } - } - } -} - -function unmask(buffer: VSBuffer, mask: number): void { - if (mask === 0) { - return; - } - let cnt = buffer.byteLength >>> 2; - for (let i = 0; i < cnt; i++) { - const v = buffer.readUInt32BE(i * 4); - buffer.writeUInt32BE(v ^ mask, i * 4); - } - let offset = cnt * 4; - let bytesLeft = buffer.byteLength - offset; - const m3 = (mask >>> 24) & 0b11111111; - const m2 = (mask >>> 16) & 0b11111111; - const m1 = (mask >>> 8) & 0b11111111; - if (bytesLeft >= 1) { - buffer.writeUInt8(buffer.readUInt8(offset) ^ m3, offset); - } - if (bytesLeft >= 2) { - buffer.writeUInt8(buffer.readUInt8(offset + 1) ^ m2, offset + 1); - } - if (bytesLeft >= 3) { - buffer.writeUInt8(buffer.readUInt8(offset + 2) ^ m1, offset + 2); - } -} - export function generateRandomPipeName(): string { const randomSuffix = generateUuid(); if (process.platform === 'win32') { diff --git a/src/vs/base/parts/tree/browser/tree.ts b/src/vs/base/parts/tree/browser/tree.ts index e13df1cdcb..14630c8174 100644 --- a/src/vs/base/parts/tree/browser/tree.ts +++ b/src/vs/base/parts/tree/browser/tree.ts @@ -254,7 +254,7 @@ export interface IDataSource { * * You should not attempt to "move" an element to a different * parent by keeping its ID. The idea here is to have tree location - * related IDs (e.g. full file path, in the Explorer example). + * related IDs (eg. full file path, in the Explorer example). */ getId(tree: ITree, element: any): string; @@ -616,7 +616,7 @@ export interface IActionProvider { hasActions(tree: ITree | null, element: any): boolean; /** - * Returns an array with the actions of the element that should show up in place right to the element in the tree. + * Returns a promise of an array with the actions of the element that should show up in place right to the element in the tree. */ - getActions(tree: ITree | null, element: any): ReadonlyArray | null; + getActions(tree: ITree | null, element: any): IAction[] | null; } diff --git a/src/vs/base/parts/tree/browser/treeModel.ts b/src/vs/base/parts/tree/browser/treeModel.ts index 19f7274239..95b4513d13 100644 --- a/src/vs/base/parts/tree/browser/treeModel.ts +++ b/src/vs/base/parts/tree/browser/treeModel.ts @@ -159,7 +159,7 @@ export class ItemRegistry { public register(item: Item): void { Assert.ok(!this.isRegistered(item.id), 'item already registered: ' + item.id); - const disposable = combinedDisposable( + const disposable = combinedDisposable([ this._onDidRevealItem.add(item.onDidReveal), this._onExpandItem.add(item.onExpand), this._onDidExpandItem.add(item.onDidExpand), @@ -171,7 +171,7 @@ export class ItemRegistry { this._onRefreshItemChildren.add(item.onRefreshChildren), this._onDidRefreshItemChildren.add(item.onDidRefreshChildren), this._onDidDisposeItem.add(item.onDidDispose) - ); + ]); this.items[item.id] = { item, disposable }; } diff --git a/src/vs/base/test/browser/hash.test.ts b/src/vs/base/test/browser/hash.test.ts new file mode 100644 index 0000000000..cff6dbe9b1 --- /dev/null +++ b/src/vs/base/test/browser/hash.test.ts @@ -0,0 +1,16 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +import * as assert from 'assert'; +import { createSHA1 } from 'vs/base/browser/hash'; + +suite('Hash', () => { + test('computeSHA1Hash', async () => { + assert.equal(await createSHA1(''), 'da39a3ee5e6b4b0d3255bfef95601890afd80709'); + assert.equal(await createSHA1('hello world'), '2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'); + assert.equal(await createSHA1('da39a3ee5e6b4b0d3255bfef95601890afd80709'), '10a34637ad661d98ba3344717656fcc76209c2f8'); + assert.equal(await createSHA1('2aae6c35c94fcfb415dbe95f408b9ce91ee846ed'), 'd6b0d82cea4269b51572b8fab43adcee9fc3cf9a'); + assert.equal(await createSHA1('öäü_?ß()<>ÖÄÜ'), 'b64beaeff9e317b0193c8e40a2431b210388eba9'); + }); +}); \ No newline at end of file diff --git a/src/vs/base/test/common/event.test.ts b/src/vs/base/test/common/event.test.ts index 91e0ca7c60..3c40821802 100644 --- a/src/vs/base/test/common/event.test.ts +++ b/src/vs/base/test/common/event.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { Event, Emitter, EventBufferer, EventMultiplexer, AsyncEmitter, IWaitUntil, PauseableEmitter } from 'vs/base/common/event'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import * as Errors from 'vs/base/common/errors'; import { timeout } from 'vs/base/common/async'; @@ -73,27 +73,6 @@ suite('Event', function () { while (bucket.length) { bucket.pop()!.dispose(); } - doc.setText('boo'); - - // noop - subscription.dispose(); - - doc.setText('boo'); - assert.equal(counter.count, 2); - }); - - test('Emitter, store', function () { - - let bucket = new DisposableStore(); - let doc = new Samples.Document3(); - let subscription = doc.onDidChange(counter.onEvent, counter, bucket); - - doc.setText('far'); - doc.setText('boo'); - - // unhook listener - bucket.clear(); - doc.setText('boo'); // noop subscription.dispose(); diff --git a/src/vs/base/test/common/lifecycle.test.ts b/src/vs/base/test/common/lifecycle.test.ts index b713c5912a..c083c3bdb8 100644 --- a/src/vs/base/test/common/lifecycle.test.ts +++ b/src/vs/base/test/common/lifecycle.test.ts @@ -42,8 +42,7 @@ suite('Lifecycle', () => { assert(!disposable.isDisposed); assert(!disposable2.isDisposed); - dispose(disposable); - dispose(disposable2); + dispose(disposable, disposable2); assert(disposable.isDisposed); assert(disposable2.isDisposed); diff --git a/src/vs/base/test/common/uri.test.ts b/src/vs/base/test/common/uri.test.ts index 75e6e813a4..4e9f685ecd 100644 --- a/src/vs/base/test/common/uri.test.ts +++ b/src/vs/base/test/common/uri.test.ts @@ -63,7 +63,7 @@ suite('URI', () => { assert.equal(URI.from({ scheme: 'http', authority: '', path: 'my/path' }).toString(), 'http:/my/path'); assert.equal(URI.from({ scheme: 'http', authority: '', path: '/my/path' }).toString(), 'http:/my/path'); //http://a-test-site.com/#test=true - assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test=true'); + assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: 'test=true' }).toString(), 'http://a-test-site.com/?test%3Dtrue'); assert.equal(URI.from({ scheme: 'http', authority: 'a-test-site.com', path: '/', query: '', fragment: 'test=true' }).toString(), 'http://a-test-site.com/#test%3Dtrue'); }); @@ -102,11 +102,11 @@ suite('URI', () => { test('with, changes', () => { assert.equal(URI.parse('before:some/file/path').with({ scheme: 'after' }).toString(), 'after:some/file/path'); - assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t=1234'); - assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t=1234'); - assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t=1234'); - assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t=1234'); - assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t=1234'); + assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', path: '/api/files/test.me', query: 't=1234' }).toString(), 'http:/api/files/test.me?t%3D1234'); + assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'http', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'http:/api/files/test.me?t%3D1234'); + assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'https', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'https:/api/files/test.me?t%3D1234'); + assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTP', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTP:/api/files/test.me?t%3D1234'); + assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'HTTPS', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'HTTPS:/api/files/test.me?t%3D1234'); assert.equal(URI.from({ scheme: 's' }).with({ scheme: 'boo', authority: '', path: '/api/files/test.me', query: 't=1234', fragment: '' }).toString(), 'boo:/api/files/test.me?t%3D1234'); }); @@ -262,11 +262,11 @@ suite('URI', () => { value = URI.file('c:\\test with %25\\path'); assert.equal(value.path, '/c:/test with %25/path'); - assert.equal(value.toString(), 'file:///c%3A/test%20with%20%25/path'); + assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/path'); value = URI.file('c:\\test with %25\\c#code'); assert.equal(value.path, '/c:/test with %25/c#code'); - assert.equal(value.toString(), 'file:///c%3A/test%20with%20%25/c%23code'); + assert.equal(value.toString(), 'file:///c%3A/test%20with%20%2525/c%23code'); value = URI.file('\\\\shares'); assert.equal(value.scheme, 'file'); @@ -376,7 +376,7 @@ suite('URI', () => { let uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008'); assert.equal(uri.query, 'LinkId=518008'); assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008'); - assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008'); + assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008'); let uri2 = URI.parse(uri.toString()); assert.equal(uri2.query, 'LinkId=518008'); @@ -385,7 +385,7 @@ suite('URI', () => { uri = URI.parse('https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü'); assert.equal(uri.query, 'LinkId=518008&foö&ké¥=üü'); assert.equal(uri.toString(true), 'https://go.microsoft.com/fwlink/?LinkId=518008&foö&ké¥=üü'); - assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId=518008&fo%C3%B6&k%C3%A9%C2%A5=%C3%BC%C3%BC'); + assert.equal(uri.toString(), 'https://go.microsoft.com/fwlink/?LinkId%3D518008%26fo%C3%B6%26k%C3%A9%C2%A5%3D%C3%BC%C3%BC'); uri2 = URI.parse(uri.toString()); assert.equal(uri2.query, 'LinkId=518008&foö&ké¥=üü'); @@ -426,57 +426,6 @@ suite('URI', () => { assert.equal(uri.toString(true), input); }); - test('Support URL specific encodings (query component) #25852', function () { - let input = 'http://example.com/over/there?name=ferret'; - assert.equal(input, URI.parse(input).toString()); - - input = 'http://example.com/over/there?name=ferret&foo=bar'; - assert.equal(input, URI.parse(input).toString()); - - input = 'attp://example.com/over/there?name=ferret'; - assert.equal('attp://example.com/over/there?name%3Dferret', URI.parse(input).toString()); - }); - - test('Uri#parse can break path-component #45515', function () { - let uri: URI; - uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2f' }); - assert.equal(uri.toString(), 's://a/o%2f'); - uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2fü' }); - assert.equal(uri.toString(), 's://a/o%2f%C3%BC'); - uri = URI.from({ scheme: 's', authority: 'a', path: '/o%2f%' }); - assert.equal(uri.toString(), 's://a/o%2f%25'); - - uri = URI.file('/test with %25/c#code'); - assert.equal(uri.path, '/test with %25/c#code'); - assert.equal(uri.toString(), 'file:///test%20with%20%25/c%23code'); - - uri = URI.from({ - scheme: 'http', - authority: 'a', - path: '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg' - }); - assert.equal(uri.path, '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg'); - assert.equal(uri.toString(), 'http://a/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg'); - - assert.equal(URI.parse(uri.toString()).path, '/o/products%2FzVNZkudXJyq8bPGTXUxx%2FBetterave-Sesame.jpg'); - assert.equal(uri.toString(), URI.parse(uri.toString()).toString()); // identity - - uri = URI.parse('s://a/p%2ft%c3%bc'); - assert.equal(uri.path, '/p%2ftü'); - - uri = URI.parse('s://a/%c3%bcp%2f-REST'); - assert.equal(uri.path, '/üp%2f-REST'); - - uri = URI.parse('s://a/%c3%bcp%2fd%c3%b6wn'); - assert.equal(uri.path, '/üp%2fdöwn'); - - //https://github.com/microsoft/vscode/issues/25852 - uri = URI.parse('http://www.test.com/path/service?authId=CN%3DQ10'); - assert.equal(uri.query, 'authId=CN%3DQ10'); - assert.equal(uri.toString(), 'http://www.test.com/path/service?authId=CN%3DQ10'); - }); - - test('URI - (de)serialize', function () { const values = [ diff --git a/src/vs/code/browser/workbench/workbench.html b/src/vs/code/browser/workbench/workbench.html index 07ac3c653d..92e4cba15f 100644 --- a/src/vs/code/browser/workbench/workbench.html +++ b/src/vs/code/browser/workbench/workbench.html @@ -13,12 +13,7 @@ diff --git a/src/vs/code/browser/workbench/workbench.js b/src/vs/code/browser/workbench/workbench.js index 7cb78f5c01..f91b531007 100644 --- a/src/vs/code/browser/workbench/workbench.js +++ b/src/vs/code/browser/workbench/workbench.js @@ -21,11 +21,7 @@ // @ts-ignore require.config({ - baseUrl: `${window.location.origin}/out`, - paths: { - 'vscode-textmate': `${window.location.origin}/node_modules/vscode-textmate/release/main`, - 'onigasm-umd': `${window.location.origin}/node_modules/onigasm-umd/release/main`, - } + baseUrl: `${window.location.origin}/out` }); // @ts-ignore @@ -36,8 +32,9 @@ ], // @ts-ignore function () { + // @ts-ignore - require('vs/workbench/browser/web.main').main(self['WINDOW_CONFIGURATION']).then(undefined, console.error); + require('vs/workbench/browser/web.main').main().then(undefined, console.error); }); }); })(); \ No newline at end of file diff --git a/src/sql/workbench/api/electron-browser/extensionHost.contribution.ts b/src/vs/code/code.main.ts similarity index 85% rename from src/sql/workbench/api/electron-browser/extensionHost.contribution.ts rename to src/vs/code/code.main.ts index 4c24e9f734..7cbce7528e 100644 --- a/src/sql/workbench/api/electron-browser/extensionHost.contribution.ts +++ b/src/vs/code/code.main.ts @@ -3,4 +3,4 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import '../browser/extensionHost.contribution.common'; +import 'vs/platform/update/node/update.config.contribution'; \ No newline at end of file diff --git a/src/vs/code/electron-browser/issue/issueReporterMain.ts b/src/vs/code/electron-browser/issue/issueReporterMain.ts index 85e0d60dc3..b982aadc0b 100644 --- a/src/vs/code/electron-browser/issue/issueReporterMain.ts +++ b/src/vs/code/electron-browser/issue/issueReporterMain.ts @@ -33,6 +33,7 @@ import { EnvironmentService } from 'vs/platform/environment/node/environmentServ import { IssueReporterModel, IssueReporterData as IssueReporterModelData } from 'vs/code/electron-browser/issue/issueReporterModel'; import { IssueReporterData, IssueReporterStyles, IssueType, ISettingsSearchIssueReporterData, IssueReporterFeatures, IssueReporterExtensionData } from 'vs/platform/issue/common/issue'; import BaseHtml from 'vs/code/electron-browser/issue/issueReporterPage'; +import { createBufferSpdLogService } from 'vs/platform/log/node/spdlogService'; import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; @@ -40,7 +41,6 @@ import { normalizeGitHubUrl } from 'vs/code/electron-browser/issue/issueReporter import { Button } from 'vs/base/browser/ui/button/button'; import { withUndefinedAsNull } from 'vs/base/common/types'; import { SystemInfo, isRemoteDiagnosticError } from 'vs/platform/diagnostics/common/diagnosticsService'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; const MAX_URL_LENGTH = 2045; @@ -300,7 +300,7 @@ export class IssueReporter extends Disposable { serviceCollection.set(IWindowsService, new WindowsService(mainProcessService)); this.environmentService = new EnvironmentService(configuration, configuration.execPath); - const logService = new SpdLogService(`issuereporter${configuration.windowId}`, this.environmentService.logsPath, getLogLevel(this.environmentService)); + const logService = createBufferSpdLogService(`issuereporter${configuration.windowId}`, getLogLevel(this.environmentService), this.environmentService.logsPath); const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); this.logService = new FollowerLogService(logLevelClient, logService); diff --git a/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts index 5c59f89bf5..f62e2f8b61 100644 --- a/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts +++ b/src/vs/code/electron-browser/sharedProcess/contrib/languagePackCachedDataCleaner.ts @@ -8,7 +8,7 @@ import * as pfs from 'vs/base/node/pfs'; import { IStringDictionary } from 'vs/base/common/collections'; import product from 'vs/platform/product/node/product'; -import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; import { ILogService } from 'vs/platform/log/common/log'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; @@ -30,13 +30,14 @@ interface LanguagePackFile { [locale: string]: LanguagePackEntry; } -export class LanguagePackCachedDataCleaner extends Disposable { +export class LanguagePackCachedDataCleaner { + + private _disposables: IDisposable[] = []; constructor( @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ILogService private readonly _logService: ILogService ) { - super(); // We have no Language pack support for dev version (run from source) // So only cleanup when we have a build version. if (this._environmentService.isBuilt) { @@ -44,6 +45,10 @@ export class LanguagePackCachedDataCleaner extends Disposable { } } + dispose(): void { + this._disposables = dispose(this._disposables); + } + private _manageCachedDataSoon(): void { let handle: any = setTimeout(async () => { handle = undefined; @@ -96,10 +101,12 @@ export class LanguagePackCachedDataCleaner extends Disposable { } }, 40 * 1000); - this._register(toDisposable(() => { - if (handle !== undefined) { - clearTimeout(handle); + this._disposables.push({ + dispose() { + if (handle !== undefined) { + clearTimeout(handle); + } } - })); + }); } } \ No newline at end of file diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index 575362160c..28b6572c9b 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -30,6 +30,7 @@ import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppen import { IWindowsService, ActiveWindowManager } from 'vs/platform/windows/common/windows'; import { WindowsService } from 'vs/platform/windows/electron-browser/windowsService'; import { ipcRenderer } from 'electron'; +import { createBufferSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; @@ -47,7 +48,6 @@ import { StorageDataCleaner } from 'vs/code/electron-browser/sharedProcess/contr import { LogsDataCleaner } from 'vs/code/electron-browser/sharedProcess/contrib/logsDataCleaner'; import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProcessService'; import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; export interface ISharedProcessConfiguration { readonly machineId: string; @@ -79,7 +79,7 @@ class MainProcessService implements IMainProcessService { } } -async function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): Promise { +function main(server: Server, initData: ISharedProcessInitData, configuration: ISharedProcessConfiguration): void { const services = new ServiceCollection(); const disposables: IDisposable[] = []; @@ -94,17 +94,14 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const mainRouter = new StaticRouter(ctx => ctx === 'main'); const logLevelClient = new LogLevelSetterChannelClient(server.getChannel('loglevel', mainRouter)); - const logService = new FollowerLogService(logLevelClient, new SpdLogService('sharedprocess', environmentService.logsPath, initData.logLevel)); + const logService = new FollowerLogService(logLevelClient, createBufferSpdLogService('sharedprocess', initData.logLevel, environmentService.logsPath)); disposables.push(logService); - logService.info('main', JSON.stringify(configuration)); - const configurationService = new ConfigurationService(environmentService.settingsResource.path); - disposables.push(configurationService); - await configurationService.initialize(); + logService.info('main', JSON.stringify(configuration)); services.set(IEnvironmentService, environmentService); services.set(ILogService, logService); - services.set(IConfigurationService, configurationService); + services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); services.set(IRequestService, new SyncDescriptor(RequestService)); services.set(IDownloadService, new SyncDescriptor(DownloadService)); @@ -125,7 +122,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat const services = new ServiceCollection(); const environmentService = accessor.get(IEnvironmentService); const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = environmentService; - const telemetryLogService = new FollowerLogService(logLevelClient, new SpdLogService('telemetry', environmentService.logsPath, initData.logLevel)); + const telemetryLogService = new FollowerLogService(logLevelClient, createBufferSpdLogService('telemetry', initData.logLevel, environmentService.logsPath)); telemetryLogService.info('The below are logs for every telemetry event sent from VS Code once the log level is set to trace.'); telemetryLogService.info('==========================================================='); @@ -168,12 +165,12 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat // update localizations cache (localizationsService as LocalizationsService).update(); // cache clean ups - disposables.push(combinedDisposable( + disposables.push(combinedDisposable([ instantiationService2.createInstance(NodeCachedDataCleaner), instantiationService2.createInstance(LanguagePackCachedDataCleaner), instantiationService2.createInstance(StorageDataCleaner), instantiationService2.createInstance(LogsDataCleaner) - )); + ])); disposables.push(extensionManagementService as ExtensionManagementService); }); }); @@ -221,6 +218,6 @@ async function handshake(configuration: ISharedProcessConfiguration): Promise - + diff --git a/src/vs/code/electron-browser/workbench/workbench.js b/src/vs/code/electron-browser/workbench/workbench.js index 1fef3b3b34..90ab9dd0a1 100644 --- a/src/vs/code/electron-browser/workbench/workbench.js +++ b/src/vs/code/electron-browser/workbench/workbench.js @@ -54,7 +54,13 @@ bootstrapWindow.load([ showPartsSplash(windowConfig); }, beforeLoaderConfig: function (windowConfig, loaderConfig) { - loaderConfig.recordStats = true; + loaderConfig.recordStats = !!windowConfig['prof-modules']; + if (loaderConfig.nodeCachedData) { + const onNodeCachedData = window['MonacoEnvironment'].onNodeCachedData = []; + loaderConfig.nodeCachedData.onData = function () { + onNodeCachedData.push(arguments); + }; + } }, beforeRequire: function () { perf.mark('willLoadWorkbenchMain'); @@ -83,7 +89,7 @@ function showPartsSplash(configuration) { } } - // high contrast mode has been turned on from the outside, e.g. OS -> ignore stored colors and layouts + // high contrast mode has been turned on from the outside, e.g OS -> ignore stored colors and layouts if (data && configuration.highContrast && data.baseTheme !== 'hc-black') { data = undefined; } diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 92a76cb94c..eae9dc72f3 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -9,7 +9,7 @@ import { WindowsManager } from 'vs/code/electron-main/windows'; import { IWindowsService, OpenContext, ActiveWindowManager, IURIToOpen } from 'vs/platform/windows/common/windows'; import { WindowsChannel } from 'vs/platform/windows/node/windowsIpc'; import { WindowsService } from 'vs/platform/windows/electron-main/windowsService'; -import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleService, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { getShellEnvironment } from 'vs/code/node/shellEnv'; import { IUpdateService } from 'vs/platform/update/common/update'; import { UpdateChannel } from 'vs/platform/update/node/updateIpc'; @@ -36,10 +36,12 @@ import { getDelayedChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; import { ProxyAuthHandler } from 'vs/code/electron-main/auth'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { ConfigurationService } from 'vs/platform/configuration/node/configurationService'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { IHistoryMainService } from 'vs/platform/history/common/history'; -import { withUndefinedAsNull } from 'vs/base/common/types'; +import { isUndefinedOrNull, withUndefinedAsNull } from 'vs/base/common/types'; +import { KeyboardLayoutMonitor } from 'vs/code/electron-main/keyboard'; import { URI } from 'vs/base/common/uri'; import { WorkspacesChannel } from 'vs/platform/workspaces/node/workspacesIpc'; import { IWorkspacesMainService, hasWorkspaceFileExtension } from 'vs/platform/workspaces/common/workspaces'; @@ -61,6 +63,7 @@ import { MenubarChannel } from 'vs/platform/menubar/node/menubarIpc'; import { hasArgs } from 'vs/platform/environment/node/argv'; import { RunOnceScheduler } from 'vs/base/common/async'; import { registerContextMenuListener } from 'vs/base/parts/contextmenu/electron-main/contextmenu'; +import { storeBackgroundColor } from 'vs/code/electron-main/theme'; import { homedir } from 'os'; import { join, sep } from 'vs/base/common/path'; import { localize } from 'vs/nls'; @@ -85,7 +88,12 @@ export class CodeApplication extends Disposable { private static readonly MACHINE_ID_KEY = 'telemetry.machineId'; - private windowsMainService: IWindowsMainService | undefined; + private windowsMainService: IWindowsMainService; + + private electronIpcServer: ElectronIPCServer; + + private sharedProcess: SharedProcess; + private sharedProcessClient: Promise; constructor( private readonly mainIpcServer: Server, @@ -94,11 +102,14 @@ export class CodeApplication extends Disposable { @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @IConfigurationService private readonly configurationService: IConfigurationService, + @IConfigurationService private readonly configurationService: ConfigurationService, @IStateService private readonly stateService: IStateService ) { super(); + this._register(mainIpcServer); + this._register(configurationService); + this.registerListeners(); } @@ -109,12 +120,12 @@ export class CodeApplication extends Disposable { process.on('uncaughtException', err => this.onUnexpectedError(err)); process.on('unhandledRejection', (reason: unknown) => onUnexpectedError(reason)); - // Dispose on shutdown - this.lifecycleService.onWillShutdown(() => this.dispose()); - // Contextmenu via IPC support registerContextMenuListener(); + // Dispose on shutdown + this.lifecycleService.onWillShutdown(() => this.dispose()); + app.on('accessibility-support-changed', (event: Event, accessibilitySupportEnabled: boolean) => { if (this.windowsMainService) { this.windowsMainService.sendToAll('vscode:accessibilitySupportChanged', accessibilitySupportEnabled); @@ -187,7 +198,7 @@ export class CodeApplication extends Disposable { event.preventDefault(); // Keep in array because more might come! - macOpenFileURIs.push(this.getURIToOpenFromPathSync(path)); + macOpenFileURIs.push(getURIToOpenFromPathSync(path)); // Clear previous handler if any if (runningTimeout !== null) { @@ -204,7 +215,6 @@ export class CodeApplication extends Disposable { urisToOpen: macOpenFileURIs, preferNewWindow: true /* dropping on the dock or opening from finder prefers to open in a new window */ }); - macOpenFileURIs = []; runningTimeout = null; } @@ -212,9 +222,7 @@ export class CodeApplication extends Disposable { }); app.on('new-window-for-tab', () => { - if (this.windowsMainService) { - this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button - } + this.windowsMainService.openNewWindow(OpenContext.DESKTOP); //macOS native tab "+" button }); ipc.on('vscode:exit', (event: Event, code: number) => { @@ -224,26 +232,37 @@ export class CodeApplication extends Disposable { this.lifecycleService.kill(code); }); - ipc.on('vscode:fetchShellEnv', async (event: Event) => { + ipc.on('vscode:fetchShellEnv', (event: Event) => { const webContents = event.sender; - - try { - const shellEnv = await getShellEnvironment(this.logService, this.environmentService); + getShellEnvironment(this.logService).then(shellEnv => { if (!webContents.isDestroyed()) { webContents.send('vscode:acceptShellEnv', shellEnv); } - } catch (error) { + }, err => { if (!webContents.isDestroyed()) { webContents.send('vscode:acceptShellEnv', {}); } - this.logService.error('Error fetching shell env', error); + this.logService.error('Error fetching shell env', err); + }); + }); + + ipc.on('vscode:broadcast', (event: Event, windowId: number, broadcast: { channel: string; payload: object; }) => { + if (this.windowsMainService && broadcast.channel && !isUndefinedOrNull(broadcast.payload)) { + this.logService.trace('IPC#vscode:broadcast', broadcast.channel, broadcast.payload); + + // Handle specific events on main side + this.onBroadcast(broadcast.channel, broadcast.payload); + + // Send to all windows (except sender window) + this.windowsMainService.sendToAll('vscode:broadcast', broadcast, [windowId]); } }); ipc.on('vscode:extensionHostDebug', (_: Event, windowId: number, broadcast: any) => { if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]); // Send to all windows (except sender window) + // Send to all windows (except sender window) + this.windowsMainService.sendToAll('vscode:extensionHostDebug', broadcast, [windowId]); } }); @@ -252,28 +271,11 @@ export class CodeApplication extends Disposable { ipc.on('vscode:reloadWindow', (event: Event) => event.sender.reload()); - // After waking up from sleep (after window opened) - (async () => { - await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen); - - powerMonitor.on('resume', () => { - if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:osResume', undefined); - } - }); - })(); - - // Keyboard layout changes (after window opened) - (async () => { - await this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen); - - const nativeKeymap = await import('native-keymap'); - nativeKeymap.onDidChangeKeyboardLayout(() => { - if (this.windowsMainService) { - this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); - } - }); - })(); + powerMonitor.on('resume', () => { // After waking up from sleep + if (this.windowsMainService) { + this.windowsMainService.sendToAll('vscode:osResume', undefined); + } + }); } private onUnexpectedError(err: Error): void { @@ -297,7 +299,15 @@ export class CodeApplication extends Disposable { } } - async startup(): Promise { + private onBroadcast(event: string, payload: object): void { + + // Theme changes + if (event === 'vscode:changeColorTheme' && typeof payload === 'string') { + storeBackgroundColor(this.stateService, JSON.parse(payload)); + } + } + + startup(): Promise { this.logService.debug('Starting VS Code'); this.logService.debug(`from: ${this.environmentService.appRoot}`); this.logService.debug('args:', this.environmentService.args); @@ -325,122 +335,64 @@ export class CodeApplication extends Disposable { } // Create Electron IPC Server - const electronIpcServer = new ElectronIPCServer(); + this.electronIpcServer = new ElectronIPCServer(); + + const startupWithMachineId = (machineId: string) => { + this.logService.trace(`Resolved machine identifier: ${machineId}`); + + // Spawn shared process + this.sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); + this.sharedProcessClient = this.sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); + + // Services + return this.initServices(machineId).then(appInstantiationService => { + + // Create driver + if (this.environmentService.driverHandle) { + serveDriver(this.electronIpcServer, this.environmentService.driverHandle, this.environmentService, appInstantiationService).then(server => { + this.logService.info('Driver started at:', this.environmentService.driverHandle); + this._register(server); + }); + } + + // Setup Auth Handler + const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); + this._register(authHandler); + + // Open Windows + const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor)); + + // Post Open Windows Tasks + appInstantiationService.invokeFunction(accessor => this.afterWindowOpen(accessor)); + + // Tracing: Stop tracing after windows are ready if enabled + if (this.environmentService.args.trace) { + this.stopTracingEventually(windows); + } + }); + }; // Resolve unique machine ID this.logService.trace('Resolving machine identifier...'); - const machineId = await this.resolveMachineId(); - this.logService.trace(`Resolved machine identifier: ${machineId}`); - - // Spawn shared process after the first window has opened and 3s have passed - const sharedProcess = this.instantiationService.createInstance(SharedProcess, machineId, this.userEnv); - const sharedProcessClient = sharedProcess.whenReady().then(() => connect(this.environmentService.sharedIPCHandle, 'main')); - this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => { - this._register(new RunOnceScheduler(async () => { - const userEnv = await getShellEnvironment(this.logService, this.environmentService); - - sharedProcess.spawn(userEnv); - }, 3000)).schedule(); - }); - - // Services - const appInstantiationService = await this.createServices(machineId, sharedProcess, sharedProcessClient); - - // Create driver - if (this.environmentService.driverHandle) { - (async () => { - const server = await serveDriver(electronIpcServer, this.environmentService.driverHandle!, this.environmentService, appInstantiationService); - - this.logService.info('Driver started at:', this.environmentService.driverHandle); - this._register(server); - })(); - } - - // Setup Auth Handler - const authHandler = appInstantiationService.createInstance(ProxyAuthHandler); - this._register(authHandler); - - // Open Windows - const windows = appInstantiationService.invokeFunction(accessor => this.openFirstWindow(accessor, electronIpcServer, sharedProcessClient)); - - // Post Open Windows Tasks - this.afterWindowOpen(); - - // Tracing: Stop tracing after windows are ready if enabled - if (this.environmentService.args.trace) { - this.stopTracingEventually(windows); - } - } - - private async resolveMachineId(): Promise { - - // We cache the machineId for faster lookups on startup - // and resolve it only once initially if not cached - let machineId = this.stateService.getItem(CodeApplication.MACHINE_ID_KEY); - if (!machineId) { - machineId = await getMachineId(); - - this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId); - } - - return machineId; - } - - private async createServices(machineId: string, sharedProcess: SharedProcess, sharedProcessClient: Promise>): Promise { - const services = new ServiceCollection(); - - switch (process.platform) { - case 'win32': - services.set(IUpdateService, new SyncDescriptor(Win32UpdateService)); - break; - - case 'linux': - if (process.env.SNAP && process.env.SNAP_REVISION) { - services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION])); - } else { - services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService)); - } - break; - - case 'darwin': - services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService)); - break; - } - - services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId, this.userEnv])); - services.set(IWindowsService, new SyncDescriptor(WindowsService, [sharedProcess])); - services.set(ILaunchService, new SyncDescriptor(LaunchService)); - services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv])); - services.set(IMenubarService, new SyncDescriptor(MenubarService)); - - const storageMainService = new StorageMainService(this.logService, this.environmentService); - services.set(IStorageMainService, storageMainService); - this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close())); - - const backupMainService = new BackupMainService(this.environmentService, this.configurationService, this.logService); - services.set(IBackupMainService, backupMainService); - - services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService)); - services.set(IURLService, new SyncDescriptor(URLService)); - services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService)); - - // Telemetry - if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { - const channel = getDelayedChannel(sharedProcessClient.then(client => client.getChannel('telemetryAppender'))); - const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); - const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath); - const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; - const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; - - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + const resolvedMachineId = this.resolveMachineId(); + if (typeof resolvedMachineId === 'string') { + return startupWithMachineId(resolvedMachineId); } else { - services.set(ITelemetryService, NullTelemetryService); + return resolvedMachineId.then(machineId => startupWithMachineId(machineId)); + } + } + + private resolveMachineId(): string | Promise { + const machineId = this.stateService.getItem(CodeApplication.MACHINE_ID_KEY); + if (machineId) { + return machineId; } - // Init services that require it - await backupMainService.initialize(); + return getMachineId().then(machineId => { + this.stateService.setItem(CodeApplication.MACHINE_ID_KEY, machineId); - return this.instantiationService.createChild(services); + return machineId; + }); } private stopTracingEventually(windows: ICodeWindow[]): void { @@ -456,14 +408,12 @@ export class CodeApplication extends Disposable { contentTracing.stopRecording(join(homedir(), `${product.applicationName}-${Math.random().toString(16).slice(-4)}.trace.txt`), path => { if (!timeout) { - if (this.windowsMainService) { - this.windowsMainService.showMessageBox({ - type: 'info', - message: localize('trace.message', "Successfully created trace."), - detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), - buttons: [localize('trace.ok', "Ok")] - }, this.windowsMainService.getLastActiveWindow()); - } + this.windowsMainService.showMessageBox({ + type: 'info', + message: localize('trace.message', "Successfully created trace."), + detail: localize('trace.detail', "Please create an issue and manually attach the following file:\n{0}", path), + buttons: [localize('trace.ok', "Ok")] + }, this.windowsMainService.getLastActiveWindow()); } else { this.logService.info(`Tracing: data recorded (after 30s timeout) to ${path}`); } @@ -480,7 +430,72 @@ export class CodeApplication extends Disposable { }); } - private openFirstWindow(accessor: ServicesAccessor, electronIpcServer: ElectronIPCServer, sharedProcessClient: Promise>): ICodeWindow[] { + private initServices(machineId: string): Promise { + const services = new ServiceCollection(); + + if (process.platform === 'win32') { + services.set(IUpdateService, new SyncDescriptor(Win32UpdateService)); + } else if (process.platform === 'linux') { + if (process.env.SNAP && process.env.SNAP_REVISION) { + services.set(IUpdateService, new SyncDescriptor(SnapUpdateService, [process.env.SNAP, process.env.SNAP_REVISION])); + } else { + services.set(IUpdateService, new SyncDescriptor(LinuxUpdateService)); + } + } else if (process.platform === 'darwin') { + services.set(IUpdateService, new SyncDescriptor(DarwinUpdateService)); + } + + services.set(IWindowsMainService, new SyncDescriptor(WindowsManager, [machineId])); + services.set(IWindowsService, new SyncDescriptor(WindowsService, [this.sharedProcess])); + services.set(ILaunchService, new SyncDescriptor(LaunchService)); + services.set(IIssueService, new SyncDescriptor(IssueService, [machineId, this.userEnv])); + services.set(IMenubarService, new SyncDescriptor(MenubarService)); + services.set(IStorageMainService, new SyncDescriptor(StorageMainService)); + services.set(IBackupMainService, new SyncDescriptor(BackupMainService)); + services.set(IHistoryMainService, new SyncDescriptor(HistoryMainService)); + services.set(IURLService, new SyncDescriptor(URLService)); + services.set(IWorkspacesMainService, new SyncDescriptor(WorkspacesMainService)); + + // Telemetry + if (!this.environmentService.isExtensionDevelopment && !this.environmentService.args['disable-telemetry'] && !!product.enableTelemetry) { + const channel = getDelayedChannel(this.sharedProcessClient.then(c => c.getChannel('telemetryAppender'))); + const appender = combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(this.logService)); + const commonProperties = resolveCommonProperties(product.commit, pkg.version, machineId, this.environmentService.installSourcePath); + const piiPaths = [this.environmentService.appRoot, this.environmentService.extensionsPath]; + const config: ITelemetryServiceConfig = { appender, commonProperties, piiPaths }; + + services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + } else { + services.set(ITelemetryService, NullTelemetryService); + } + + const appInstantiationService = this.instantiationService.createChild(services); + + // Init services that require it + return appInstantiationService.invokeFunction(accessor => Promise.all([ + this.initStorageService(accessor), + this.initBackupService(accessor) + ])).then(() => appInstantiationService); + } + + private initStorageService(accessor: ServicesAccessor): Promise { + const storageMainService = accessor.get(IStorageMainService) as StorageMainService; + + // Ensure to close storage on shutdown + this.lifecycleService.onWillShutdown(e => e.join(storageMainService.close())); + + return Promise.resolve(); + + } + + private initBackupService(accessor: ServicesAccessor): Promise { + const backupMainService = accessor.get(IBackupMainService) as BackupMainService; + + return backupMainService.initialize(); + } + + private openFirstWindow(accessor: ServicesAccessor): ICodeWindow[] { + const appInstantiationService = accessor.get(IInstantiationService); // Register more Main IPC services const launchService = accessor.get(ILaunchService); @@ -490,40 +505,40 @@ export class CodeApplication extends Disposable { // Register more Electron IPC services const updateService = accessor.get(IUpdateService); const updateChannel = new UpdateChannel(updateService); - electronIpcServer.registerChannel('update', updateChannel); + this.electronIpcServer.registerChannel('update', updateChannel); const issueService = accessor.get(IIssueService); const issueChannel = new IssueChannel(issueService); - electronIpcServer.registerChannel('issue', issueChannel); + this.electronIpcServer.registerChannel('issue', issueChannel); const workspacesService = accessor.get(IWorkspacesMainService); - const workspacesChannel = new WorkspacesChannel(workspacesService); - electronIpcServer.registerChannel('workspaces', workspacesChannel); + const workspacesChannel = appInstantiationService.createInstance(WorkspacesChannel, workspacesService); + this.electronIpcServer.registerChannel('workspaces', workspacesChannel); const windowsService = accessor.get(IWindowsService); const windowsChannel = new WindowsChannel(windowsService); - electronIpcServer.registerChannel('windows', windowsChannel); - sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); + this.electronIpcServer.registerChannel('windows', windowsChannel); + this.sharedProcessClient.then(client => client.registerChannel('windows', windowsChannel)); const menubarService = accessor.get(IMenubarService); const menubarChannel = new MenubarChannel(menubarService); - electronIpcServer.registerChannel('menubar', menubarChannel); + this.electronIpcServer.registerChannel('menubar', menubarChannel); const urlService = accessor.get(IURLService); const urlChannel = new URLServiceChannel(urlService); - electronIpcServer.registerChannel('url', urlChannel); + this.electronIpcServer.registerChannel('url', urlChannel); const storageMainService = accessor.get(IStorageMainService); const storageChannel = this._register(new GlobalStorageDatabaseChannel(this.logService, storageMainService as StorageMainService)); - electronIpcServer.registerChannel('storage', storageChannel); + this.electronIpcServer.registerChannel('storage', storageChannel); // Log level management const logLevelChannel = new LogLevelSetterChannel(accessor.get(ILogService)); - electronIpcServer.registerChannel('loglevel', logLevelChannel); - sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); + this.electronIpcServer.registerChannel('loglevel', logLevelChannel); + this.sharedProcessClient.then(client => client.registerChannel('loglevel', logLevelChannel)); - // Signal phase: ready (services set) - this.lifecycleService.phase = LifecycleMainPhase.Ready; + // Lifecycle + (this.lifecycleService as LifecycleService).ready(); // Propagate to clients const windowsMainService = this.windowsMainService = accessor.get(IWindowsMainService); // TODO@Joao: unfold this @@ -531,7 +546,7 @@ export class CodeApplication extends Disposable { // Create a URL handler which forwards to the last active window const activeWindowManager = new ActiveWindowManager(windowsService); const activeWindowRouter = new StaticRouter(ctx => activeWindowManager.getActiveClientId().then(id => ctx === id)); - const urlHandlerChannel = electronIpcServer.getChannel('urlHandler', activeWindowRouter); + const urlHandlerChannel = this.electronIpcServer.getChannel('urlHandler', activeWindowRouter); const multiplexURLHandler = new URLHandlerChannelClient(urlHandlerChannel); // On Mac, Code can be running without any open windows, so we must create a window to handle urls, @@ -540,17 +555,15 @@ export class CodeApplication extends Disposable { const environmentService = accessor.get(IEnvironmentService); urlService.registerHandler({ - async handleURL(uri: URI): Promise { + handleURL(uri: URI): Promise { if (windowsMainService.getWindowCount() === 0) { const cli = { ...environmentService.args, goto: true }; const [window] = windowsMainService.open({ context: OpenContext.API, cli, forceEmpty: true }); - await window.ready(); - - return urlService.open(uri); + return window.ready().then(() => urlService.open(uri)); } - return false; + return Promise.resolve(false); } }); } @@ -561,9 +574,11 @@ export class CodeApplication extends Disposable { // Watch Electron URLs and forward them to the UrlService const args = this.environmentService.args; const urls = args['open-url'] ? args._urls : []; - const urlListener = new ElectronURLListener(urls || [], urlService, windowsMainService); + const urlListener = new ElectronURLListener(urls || [], urlService, this.windowsMainService); this._register(urlListener); + this.windowsMainService.ready(this.userEnv); + // Open our first window const macOpenFiles: string[] = (global).macOpenFiles; const context = !!process.env['VSCODE_CLI'] ? OpenContext.CLI : OpenContext.DESKTOP; @@ -573,9 +588,9 @@ export class CodeApplication extends Disposable { const noRecentEntry = args['skip-add-to-recently-opened'] === true; const waitMarkerFileURI = args.wait && args.waitMarkerFilePath ? URI.file(args.waitMarkerFilePath) : undefined; - // new window if "-n" was used without paths if (args['new-window'] && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - return windowsMainService.open({ + // new window if "-n" was used without paths + return this.windowsMainService.open({ context, cli: args, forceNewWindow: true, @@ -586,12 +601,12 @@ export class CodeApplication extends Disposable { }); } - // mac: open-file event received on startup if (macOpenFiles && macOpenFiles.length && !hasCliArgs && !hasFolderURIs && !hasFileURIs) { - return windowsMainService.open({ + // mac: open-file event received on startup + return this.windowsMainService.open({ context: OpenContext.DOCK, cli: args, - urisToOpen: macOpenFiles.map(file => this.getURIToOpenFromPathSync(file)), + urisToOpen: macOpenFiles.map(getURIToOpenFromPathSync), noRecentEntry, waitMarkerFileURI, initialStartup: true @@ -599,7 +614,7 @@ export class CodeApplication extends Disposable { } // default: read paths from cli - return windowsMainService.open({ + return this.windowsMainService.open({ context, cli: args, forceNewWindow: args['new-window'] || (!hasCliArgs && args['unity-launch']), @@ -610,30 +625,61 @@ export class CodeApplication extends Disposable { }); } - private getURIToOpenFromPathSync(path: string): IURIToOpen { - try { - const fileStat = statSync(path); - if (fileStat.isDirectory()) { - return { folderUri: URI.file(path) }; + private afterWindowOpen(accessor: ServicesAccessor): void { + const windowsMainService = accessor.get(IWindowsMainService); + const historyMainService = accessor.get(IHistoryMainService); + + if (isWindows) { + + // Setup Windows mutex + try { + const Mutex = (require.__$__nodeRequire('windows-mutex') as any).Mutex; + const windowsMutex = new Mutex(product.win32MutexName); + this._register(toDisposable(() => windowsMutex.release())); + } catch (e) { + if (!this.environmentService.isBuilt) { + windowsMainService.showMessageBox({ + title: product.nameLong, + type: 'warning', + message: 'Failed to load windows-mutex!', + detail: e.toString(), + noLink: true + }); + } } - if (hasWorkspaceFileExtension(path)) { - return { workspaceUri: URI.file(path) }; + // Ensure Windows foreground love module + try { + // tslint:disable-next-line:no-unused-expression + require.__$__nodeRequire('windows-foreground-love'); + } catch (e) { + if (!this.environmentService.isBuilt) { + windowsMainService.showMessageBox({ + title: product.nameLong, + type: 'warning', + message: 'Failed to load windows-foreground-love!', + detail: e.toString(), + noLink: true + }); + } } - } catch (error) { - // ignore errors } - return { fileUri: URI.file(path) }; - } - - private afterWindowOpen(): void { - - // Signal phase: after window open - this.lifecycleService.phase = LifecycleMainPhase.AfterWindowOpen; - // Remote Authorities this.handleRemoteAuthorities(); + + // Keyboard layout changes + KeyboardLayoutMonitor.INSTANCE.onDidChangeKeyboardLayout(() => { + this.windowsMainService.sendToAll('vscode:keyboardLayoutChanged', false); + }); + + // Jump List + historyMainService.updateWindowsJumpList(); + historyMainService.onRecentlyOpenedChange(() => historyMainService.updateWindowsJumpList()); + + // Start shared process after a while + const sharedProcessSpawn = this._register(new RunOnceScheduler(() => getShellEnvironment(this.logService).then(userEnv => this.sharedProcess.spawn(userEnv)), 3000)); + sharedProcessSpawn.schedule(); } private handleRemoteAuthorities(): void { @@ -648,9 +694,8 @@ export class CodeApplication extends Disposable { constructor(authority: string, host: string, port: number) { this._authority = authority; - const options: IConnectionOptions = { - isBuilt, + isBuilt: isBuilt, commit: product.commit, webSocketFactory: nodeWebSocketFactory, addressProvider: { @@ -659,7 +704,6 @@ export class CodeApplication extends Disposable { } } }; - this._connection = connectRemoteAgentManagement(options, authority, `main`); this._disposeRunner = new RunOnceScheduler(() => this.dispose(), 5000); } @@ -667,13 +711,14 @@ export class CodeApplication extends Disposable { dispose(): void { this._disposeRunner.dispose(); connectionPool.delete(this._authority); - this._connection.then(connection => connection.dispose()); + this._connection.then((connection) => { + connection.dispose(); + }); } async getClient(): Promise> { this._disposeRunner.schedule(); const connection = await this._connection; - return connection.client; } } @@ -681,9 +726,7 @@ export class CodeApplication extends Disposable { const resolvedAuthorities = new Map(); ipc.on('vscode:remoteAuthorityResolved', (event: Electron.Event, data: ResolvedAuthority) => { this.logService.info('Received resolved authority', data.authority); - resolvedAuthorities.set(data.authority, data); - // Make sure to close and remove any existing connections if (connectionPool.has(data.authority)) { connectionPool.get(data.authority)!.dispose(); @@ -692,19 +735,15 @@ export class CodeApplication extends Disposable { const resolveAuthority = (authority: string): ResolvedAuthority | null => { this.logService.info('Resolving authority', authority); - if (authority.indexOf('+') >= 0) { if (resolvedAuthorities.has(authority)) { return withUndefinedAsNull(resolvedAuthorities.get(authority)); } - this.logService.info('Didnot find resolved authority for', authority); - return null; } else { const [host, strPort] = authority.split(':'); const port = parseInt(strPort, 10); - return { authority, host, port }; } }; @@ -713,7 +752,6 @@ export class CodeApplication extends Disposable { if (request.method !== 'GET') { return callback(undefined); } - const uri = URI.parse(request.url); let activeConnection: ActiveConnection | undefined; @@ -725,11 +763,9 @@ export class CodeApplication extends Disposable { callback(undefined); return; } - activeConnection = new ActiveConnection(uri.authority, resolvedAuthority.host, resolvedAuthority.port); connectionPool.set(uri.authority, activeConnection); } - try { const rawClient = await activeConnection!.getClient(); if (connectionPool.has(uri.authority)) { // not disposed in the meantime @@ -748,3 +784,16 @@ export class CodeApplication extends Disposable { }); } } + +function getURIToOpenFromPathSync(path: string): IURIToOpen { + try { + const fileStat = statSync(path); + if (fileStat.isDirectory()) { + return { folderUri: URI.file(path) }; + } else if (hasWorkspaceFileExtension(path)) { + return { workspaceUri: URI.file(path) }; + } + } catch (error) { + } + return { fileUri: URI.file(path) }; +} diff --git a/src/vs/code/electron-main/keyboard.ts b/src/vs/code/electron-main/keyboard.ts new file mode 100644 index 0000000000..aad1b04a88 --- /dev/null +++ b/src/vs/code/electron-main/keyboard.ts @@ -0,0 +1,32 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import * as nativeKeymap from 'native-keymap'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { Emitter } from 'vs/base/common/event'; + +export class KeyboardLayoutMonitor { + + public static readonly INSTANCE = new KeyboardLayoutMonitor(); + + private readonly _emitter: Emitter; + private _registered: boolean; + + private constructor() { + this._emitter = new Emitter(); + this._registered = false; + } + + public onDidChangeKeyboardLayout(callback: () => void): IDisposable { + if (!this._registered) { + this._registered = true; + + nativeKeymap.onDidChangeKeyboardLayout(() => { + this._emitter.fire(); + }); + } + return this._emitter.event(callback); + } +} \ No newline at end of file diff --git a/src/vs/code/electron-main/logUploader.ts b/src/vs/code/electron-main/logUploader.ts index 5676a395c5..811718d4ab 100644 --- a/src/vs/code/electron-main/logUploader.ts +++ b/src/vs/code/electron-main/logUploader.ts @@ -22,10 +22,10 @@ interface PostResult { class Endpoint { private constructor( - readonly url: string + public readonly url: string ) { } - static getFromProduct(): Endpoint | undefined { + public static getFromProduct(): Endpoint | undefined { const logUploaderUrl = product.logUploaderUrl; return logUploaderUrl ? new Endpoint(logUploaderUrl) : undefined; } diff --git a/src/vs/code/electron-main/main.ts b/src/vs/code/electron-main/main.ts index 2e86a42d1a..111fc412cd 100644 --- a/src/vs/code/electron-main/main.ts +++ b/src/vs/code/electron-main/main.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/platform/update/node/update.config.contribution'; +import 'vs/code/code.main'; import { app, dialog } from 'electron'; import { assign } from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; @@ -32,184 +32,76 @@ import * as fs from 'fs'; import { CodeApplication } from 'vs/code/electron-main/app'; import { localize } from 'vs/nls'; import { mnemonicButtonLabel } from 'vs/base/common/labels'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; +import { createSpdLogService } from 'vs/platform/log/node/spdlogService'; import { IDiagnosticsService, DiagnosticsService } from 'vs/platform/diagnostics/electron-main/diagnosticsService'; import { BufferLogService } from 'vs/platform/log/common/bufferLog'; import { uploadLogs } from 'vs/code/electron-main/logUploader'; import { setUnexpectedErrorHandler } from 'vs/base/common/errors'; -import { IThemeMainService, ThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; -import { Client } from 'vs/base/parts/ipc/common/ipc.net'; -import { once } from 'vs/base/common/functional'; class ExpectedError extends Error { readonly isExpected = true; } -class CodeMain { +function setupIPC(accessor: ServicesAccessor): Promise { + const logService = accessor.get(ILogService); + const environmentService = accessor.get(IEnvironmentService); + const instantiationService = accessor.get(IInstantiationService); - main(): void { + function allowSetForegroundWindow(service: LaunchChannelClient): Promise { + let promise: Promise = Promise.resolve(); + if (platform.isWindows) { + promise = service.getMainProcessId() + .then(processId => { + logService.trace('Sending some foreground love to the running instance:', processId); - // Set the error handler early enough so that we are not getting the - // default electron error dialog popping up - setUnexpectedErrorHandler(err => console.error(err)); - - // Parse arguments - let args: ParsedArgs; - try { - args = parseMainProcessArgv(process.argv); - args = validatePaths(args); - } catch (err) { - console.error(err.message); - app.exit(1); - - return; + try { + const { allowSetForegroundWindow } = require.__$__nodeRequire('windows-foreground-love'); + allowSetForegroundWindow(processId); + } catch (e) { + // noop + } + }); } - // If we are started with --wait create a random temporary file - // and pass it over to the starting instance. We can use this file - // to wait for it to be deleted to monitor that the edited file - // is closed and then exit the waiting process. - // - // Note: we are not doing this if the wait marker has been already - // added as argument. This can happen if Code was started from CLI. - if (args.wait && !args.waitMarkerFilePath) { - const waitMarkerFilePath = createWaitMarkerFile(args.verbose); - if (waitMarkerFilePath) { - addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); - args.waitMarkerFilePath = waitMarkerFilePath; + return promise; + } + + function setup(retry: boolean): Promise { + return serve(environmentService.mainIPCHandle).then(server => { + + // Print --status usage info + if (environmentService.args.status) { + logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.'); + throw new ExpectedError('Terminating...'); } - } - // Launch - this.startup(args); - } + // Log uploader usage info + if (typeof environmentService.args['upload-logs'] !== 'undefined') { + logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.'); + throw new ExpectedError('Terminating...'); + } - private async startup(args: ParsedArgs): Promise { + // dock might be hidden at this case due to a retry + if (platform.isMacintosh) { + app.dock.show(); + } - // We need to buffer the spdlog logs until we are sure - // we are the only instance running, otherwise we'll have concurrent - // log file access on Windows (https://github.com/Microsoft/vscode/issues/41218) - const bufferLogService = new BufferLogService(); + // Set the VSCODE_PID variable here when we are sure we are the first + // instance to startup. Otherwise we would wrongly overwrite the PID + process.env['VSCODE_PID'] = String(process.pid); - const [instantiationService, instanceEnvironment] = this.createServices(args, bufferLogService); - try { - - // Init services - await instantiationService.invokeFunction(async accessor => { - const environmentService = accessor.get(IEnvironmentService); - const configurationService = accessor.get(IConfigurationService); - const stateService = accessor.get(IStateService); - - try { - await this.initServices(environmentService, configurationService as ConfigurationService, stateService as StateService); - } catch (error) { - - // Show a dialog for errors that can be resolved by the user - this.handleStartupDataDirError(environmentService, error); - - throw error; - } - }); - - // Startup - await instantiationService.invokeFunction(async accessor => { - const environmentService = accessor.get(IEnvironmentService); - const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleService); - const configurationService = accessor.get(IConfigurationService); - - const mainIpcServer = await this.doStartup(logService, environmentService, lifecycleService, instantiationService, true); - - bufferLogService.logger = new SpdLogService('main', environmentService.logsPath, bufferLogService.getLevel()); - once(lifecycleService.onWillShutdown)(() => (configurationService as ConfigurationService).dispose()); - - return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); - }); - } catch (error) { - instantiationService.invokeFunction(this.quit, error); - } - } - - private createServices(args: ParsedArgs, bufferLogService: BufferLogService): [IInstantiationService, typeof process.env] { - const services = new ServiceCollection(); - - const environmentService = new EnvironmentService(args, process.execPath); - const instanceEnvironment = this.patchEnvironment(environmentService); // Patch `process.env` with the instance's environment - services.set(IEnvironmentService, environmentService); - - const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]); - process.once('exit', () => logService.dispose()); - services.set(ILogService, logService); - - services.set(IConfigurationService, new ConfigurationService(environmentService.settingsResource.path)); - services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); - services.set(IStateService, new SyncDescriptor(StateService)); - services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); - services.set(IThemeMainService, new SyncDescriptor(ThemeMainService)); - - return [new InstantiationService(services, true), instanceEnvironment]; - } - - private initServices(environmentService: IEnvironmentService, configurationService: ConfigurationService, stateService: StateService): Promise { - - // Environment service (paths) - const environmentServiceInitialization = Promise.all([ - environmentService.extensionsPath, - environmentService.nodeCachedDataDir, - environmentService.logsPath, - environmentService.globalStorageHome, - environmentService.workspaceStorageHome, - environmentService.backupHome - ].map((path): undefined | Promise => path ? mkdirp(path) : undefined)); - - // Configuration service - const configurationServiceInitialization = configurationService.initialize(); - - // State service - const stateServiceInitialization = stateService.init(); - - return Promise.all([environmentServiceInitialization, configurationServiceInitialization, stateServiceInitialization]); - } - - private patchEnvironment(environmentService: IEnvironmentService): typeof process.env { - const instanceEnvironment: typeof process.env = { - VSCODE_IPC_HOOK: environmentService.mainIPCHandle, - VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'], - VSCODE_LOGS: process.env['VSCODE_LOGS'], - // {{SQL CARBON EDIT}} We keep VSCODE_LOGS to not break functionality for merged code - ADS_LOGS: process.env['ADS_LOGS'] - }; - - if (process.env['VSCODE_PORTABLE']) { - instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE']; - } - - assign(process.env, instanceEnvironment); - - return instanceEnvironment; - } - - private async doStartup(logService: ILogService, environmentService: IEnvironmentService, lifecycleService: ILifecycleService, instantiationService: IInstantiationService, retry: boolean): Promise { - - // Try to setup a server for running. If that succeeds it means - // we are the first instance to startup. Otherwise it is likely - // that another instance is already running. - let server: Server; - try { - server = await serve(environmentService.mainIPCHandle); - once(lifecycleService.onWillShutdown)(() => server.dispose()); - } catch (error) { + return server; + }, err => { // Handle unexpected errors (the only expected error is EADDRINUSE that // indicates a second instance of Code is running) - if (error.code !== 'EADDRINUSE') { + if (err.code !== 'EADDRINUSE') { // Show a dialog for errors that can be resolved by the user - this.handleStartupDataDirError(environmentService, error); + handleStartupDataDirError(environmentService, err); // Any other runtime error is just printed to the console - throw error; + return Promise.reject(err); } // Since we are the second instance, we do not want to show the dock @@ -218,188 +110,263 @@ class CodeMain { } // there's a running instance, let's connect to it - let client: Client; - try { - client = await connect(environmentService.mainIPCHandle, 'main'); - } catch (error) { + return connect(environmentService.mainIPCHandle, 'main').then( + client => { - // Handle unexpected connection errors by showing a dialog to the user - if (!retry || platform.isWindows || error.code !== 'ECONNREFUSED') { - if (error.code === 'EPERM') { - this.showStartupWarningDialog( - localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort), - localize('secondInstanceAdminDetail', "Please close the other instance and try again.") - ); + // Tests from CLI require to be the only instance currently + if (environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break) { + const msg = 'Running extension tests from the command line is currently only supported if no other instance of Code is running.'; + logService.error(msg); + client.dispose(); + + return Promise.reject(new Error(msg)); } - throw error; + // Show a warning dialog after some timeout if it takes long to talk to the other instance + // Skip this if we are running with --wait where it is expected that we wait for a while. + // Also skip when gathering diagnostics (--status) which can take a longer time. + let startupWarningDialogHandle: NodeJS.Timeout; + if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) { + startupWarningDialogHandle = setTimeout(() => { + showStartupWarningDialog( + localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort), + localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.") + ); + }, 10000); + } + + const channel = client.getChannel('launch'); + const service = new LaunchChannelClient(channel); + + // Process Info + if (environmentService.args.status) { + return instantiationService.invokeFunction(accessor => { + return accessor.get(IDiagnosticsService).getDiagnostics(service).then(diagnostics => { + console.log(diagnostics); + return Promise.reject(new ExpectedError()); + }); + }); + } + + // Log uploader + if (typeof environmentService.args['upload-logs'] !== 'undefined') { + return instantiationService.invokeFunction(accessor => { + return uploadLogs(service, accessor.get(IRequestService), environmentService) + .then(() => Promise.reject(new ExpectedError())); + }); + } + + logService.trace('Sending env to running instance...'); + + return allowSetForegroundWindow(service) + .then(() => service.start(environmentService.args, process.env as platform.IProcessEnvironment)) + .then(() => client.dispose()) + .then(() => { + + // Now that we started, make sure the warning dialog is prevented + if (startupWarningDialogHandle) { + clearTimeout(startupWarningDialogHandle); + } + + return Promise.reject(new ExpectedError('Sent env to running instance. Terminating...')); + }); + }, + err => { + if (!retry || platform.isWindows || err.code !== 'ECONNREFUSED') { + if (err.code === 'EPERM') { + showStartupWarningDialog( + localize('secondInstanceAdmin', "A second instance of {0} is already running as administrator.", product.nameShort), + localize('secondInstanceAdminDetail', "Please close the other instance and try again.") + ); + } + + return Promise.reject(err); + } + + // it happens on Linux and OS X that the pipe is left behind + // let's delete it, since we can't connect to it + // and then retry the whole thing + try { + fs.unlinkSync(environmentService.mainIPCHandle); + } catch (e) { + logService.warn('Could not delete obsolete instance handle', e); + return Promise.reject(e); + } + + return setup(false); } - - // it happens on Linux and OS X that the pipe is left behind - // let's delete it, since we can't connect to it and then - // retry the whole thing - try { - fs.unlinkSync(environmentService.mainIPCHandle); - } catch (error) { - logService.warn('Could not delete obsolete instance handle', error); - - throw error; - } - - return this.doStartup(logService, environmentService, lifecycleService, instantiationService, false); - } - - // Tests from CLI require to be the only instance currently - if (environmentService.extensionTestsLocationURI && !environmentService.debugExtensionHost.break) { - const msg = 'Running extension tests from the command line is currently only supported if no other instance of Code is running.'; - logService.error(msg); - client.dispose(); - - throw new Error(msg); - } - - // Show a warning dialog after some timeout if it takes long to talk to the other instance - // Skip this if we are running with --wait where it is expected that we wait for a while. - // Also skip when gathering diagnostics (--status) which can take a longer time. - let startupWarningDialogHandle: NodeJS.Timeout | undefined = undefined; - if (!environmentService.wait && !environmentService.status && !environmentService.args['upload-logs']) { - startupWarningDialogHandle = setTimeout(() => { - this.showStartupWarningDialog( - localize('secondInstanceNoResponse', "Another instance of {0} is running but not responding", product.nameShort), - localize('secondInstanceNoResponseDetail', "Please close all other instances and try again.") - ); - }, 10000); - } - - const channel = client.getChannel('launch'); - const launchClient = new LaunchChannelClient(channel); - - // Process Info - if (environmentService.args.status) { - return instantiationService.invokeFunction(async accessor => { - const diagnostics = await accessor.get(IDiagnosticsService).getDiagnostics(launchClient); - console.log(diagnostics); - - throw new ExpectedError(); - }); - } - - // Log uploader - if (typeof environmentService.args['upload-logs'] !== 'undefined') { - return instantiationService.invokeFunction(async accessor => { - await uploadLogs(launchClient, accessor.get(IRequestService), environmentService); - - throw new ExpectedError(); - }); - } - - - // Windows: allow to set foreground - if (platform.isWindows) { - await this.windowsAllowSetForegroundWindow(launchClient, logService); - } - - // Send environment over... - logService.trace('Sending env to running instance...'); - await launchClient.start(environmentService.args, process.env as platform.IProcessEnvironment); - - // Cleanup - await client.dispose(); - - // Now that we started, make sure the warning dialog is prevented - if (startupWarningDialogHandle) { - clearTimeout(startupWarningDialogHandle); - } - - throw new ExpectedError('Sent env to running instance. Terminating...'); - } - - // Print --status usage info - if (environmentService.args.status) { - logService.warn('Warning: The --status argument can only be used if Code is already running. Please run it again after Code has started.'); - - throw new ExpectedError('Terminating...'); - } - - // Log uploader usage info - if (typeof environmentService.args['upload-logs'] !== 'undefined') { - logService.warn('Warning: The --upload-logs argument can only be used if Code is already running. Please run it again after Code has started.'); - - throw new ExpectedError('Terminating...'); - } - - // dock might be hidden at this case due to a retry - if (platform.isMacintosh) { - app.dock.show(); - } - - // Set the VSCODE_PID variable here when we are sure we are the first - // instance to startup. Otherwise we would wrongly overwrite the PID - process.env['VSCODE_PID'] = String(process.pid); - - return server; - } - - private handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void { - if (error.code === 'EACCES' || error.code === 'EPERM') { - this.showStartupWarningDialog( - localize('startupDataDirError', "Unable to write program user data."), - localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) ); - } - } - - private showStartupWarningDialog(message: string, detail: string): void { - dialog.showMessageBox({ - title: product.nameLong, - type: 'warning', - buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], - message, - detail, - noLink: true }); } - private async windowsAllowSetForegroundWindow(client: LaunchChannelClient, logService: ILogService): Promise { - if (platform.isWindows) { - const processId = await client.getMainProcessId(); + return setup(true); +} - logService.trace('Sending some foreground love to the running instance:', processId); +function showStartupWarningDialog(message: string, detail: string): void { + dialog.showMessageBox({ + title: product.nameLong, + type: 'warning', + buttons: [mnemonicButtonLabel(localize({ key: 'close', comment: ['&& denotes a mnemonic'] }, "&&Close"))], + message, + detail, + noLink: true + }); +} - try { - (await import('windows-foreground-love')).allowSetForegroundWindow(processId); - } catch (error) { - logService.error(error); - } - } - } - - private quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { - const logService = accessor.get(ILogService); - const lifecycleService = accessor.get(ILifecycleService); - - let exitCode = 0; - - if (reason) { - if ((reason as ExpectedError).isExpected) { - if (reason.message) { - logService.trace(reason.message); - } - } else { - exitCode = 1; // signal error to the outside - - if (reason.stack) { - logService.error(reason.stack); - } else { - logService.error(`Startup error: ${reason.toString()}`); - } - } - } - - lifecycleService.kill(exitCode); +function handleStartupDataDirError(environmentService: IEnvironmentService, error: NodeJS.ErrnoException): void { + if (error.code === 'EACCES' || error.code === 'EPERM') { + showStartupWarningDialog( + localize('startupDataDirError', "Unable to write program user data."), + localize('startupDataDirErrorDetail', "Please make sure the directories {0} and {1} are writeable.", environmentService.userDataPath, environmentService.extensionsPath) + ); } } -// Main Startup -const code = new CodeMain(); -code.main(); \ No newline at end of file +function quit(accessor: ServicesAccessor, reason?: ExpectedError | Error): void { + const logService = accessor.get(ILogService); + const lifecycleService = accessor.get(ILifecycleService); + + let exitCode = 0; + + if (reason) { + if ((reason as ExpectedError).isExpected) { + if (reason.message) { + logService.trace(reason.message); + } + } else { + exitCode = 1; // signal error to the outside + + if (reason.stack) { + logService.error(reason.stack); + } else { + logService.error(`Startup error: ${reason.toString()}`); + } + } + } + + lifecycleService.kill(exitCode); +} + +function patchEnvironment(environmentService: IEnvironmentService): typeof process.env { + const instanceEnvironment: typeof process.env = { + VSCODE_IPC_HOOK: environmentService.mainIPCHandle, + VSCODE_NLS_CONFIG: process.env['VSCODE_NLS_CONFIG'], + VSCODE_LOGS: process.env['VSCODE_LOGS'], + // {{SQL CARBON EDIT}} We keep VSCODE_LOGS to not break functionality for merged code + ADS_LOGS: process.env['ADS_LOGS'] + }; + + if (process.env['VSCODE_PORTABLE']) { + instanceEnvironment['VSCODE_PORTABLE'] = process.env['VSCODE_PORTABLE']; + } + + assign(process.env, instanceEnvironment); + + return instanceEnvironment; +} + +function startup(args: ParsedArgs): void { + + // We need to buffer the spdlog logs until we are sure + // we are the only instance running, otherwise we'll have concurrent + // log file access on Windows (https://github.com/Microsoft/vscode/issues/41218) + const bufferLogService = new BufferLogService(); + + const instantiationService = createServices(args, bufferLogService); + instantiationService.invokeFunction(accessor => { + const environmentService = accessor.get(IEnvironmentService); + const stateService = accessor.get(IStateService); + + // Patch `process.env` with the instance's environment + const instanceEnvironment = patchEnvironment(environmentService); + + // Startup + return initServices(environmentService, stateService as StateService) + .then(() => instantiationService.invokeFunction(setupIPC), error => { + + // Show a dialog for errors that can be resolved by the user + handleStartupDataDirError(environmentService, error); + + return Promise.reject(error); + }) + .then(mainIpcServer => { + createSpdLogService('main', bufferLogService.getLevel(), environmentService.logsPath).then(logger => bufferLogService.logger = logger); + + return instantiationService.createInstance(CodeApplication, mainIpcServer, instanceEnvironment).startup(); + }); + }).then(null, err => instantiationService.invokeFunction(quit, err)); +} + +function createServices(args: ParsedArgs, bufferLogService: BufferLogService): IInstantiationService { + const services = new ServiceCollection(); + + const environmentService = new EnvironmentService(args, process.execPath); + + const logService = new MultiplexLogService([new ConsoleLogMainService(getLogLevel(environmentService)), bufferLogService]); + process.once('exit', () => logService.dispose()); + + services.set(IEnvironmentService, environmentService); + services.set(ILogService, logService); + services.set(ILifecycleService, new SyncDescriptor(LifecycleService)); + services.set(IStateService, new SyncDescriptor(StateService)); + services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); + services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IDiagnosticsService, new SyncDescriptor(DiagnosticsService)); + + return new InstantiationService(services, true); +} + +function initServices(environmentService: IEnvironmentService, stateService: StateService): Promise { + + // Ensure paths for environment service exist + const environmentServiceInitialization = Promise.all([ + environmentService.extensionsPath, + environmentService.nodeCachedDataDir, + environmentService.logsPath, + environmentService.globalStorageHome, + environmentService.workspaceStorageHome, + environmentService.backupHome + ].map((path): undefined | Promise => path ? mkdirp(path) : undefined)); + + // State service + const stateServiceInitialization = stateService.init(); + + return Promise.all([environmentServiceInitialization, stateServiceInitialization]); +} + +function main(): void { + + // Set the error handler early enough so that we are not getting the + // default electron error dialog popping up + setUnexpectedErrorHandler(err => console.error(err)); + + // Parse arguments + let args: ParsedArgs; + try { + args = parseMainProcessArgv(process.argv); + args = validatePaths(args); + } catch (err) { + console.error(err.message); + app.exit(1); + + return undefined; + } + + // If we are started with --wait create a random temporary file + // and pass it over to the starting instance. We can use this file + // to wait for it to be deleted to monitor that the edited file + // is closed and then exit the waiting process. + // + // Note: we are not doing this if the wait marker has been already + // added as argument. This can happen if Code was started from CLI. + if (args.wait && !args.waitMarkerFilePath) { + const waitMarkerFilePath = createWaitMarkerFile(args.verbose); + if (waitMarkerFilePath) { + addArg(process.argv, '--waitMarkerFilePath', waitMarkerFilePath); + args.waitMarkerFilePath = waitMarkerFilePath; + } + } + startup(args); +} + +main(); diff --git a/src/vs/code/electron-main/sharedProcess.ts b/src/vs/code/electron-main/sharedProcess.ts index 7f340f2f2f..af04e4b519 100644 --- a/src/vs/code/electron-main/sharedProcess.ts +++ b/src/vs/code/electron-main/sharedProcess.ts @@ -11,7 +11,8 @@ import { ISharedProcess } from 'vs/platform/windows/electron-main/windows'; import { Barrier } from 'vs/base/common/async'; import { ILogService } from 'vs/platform/log/common/log'; import { ILifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; -import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; +import { IStateService } from 'vs/platform/state/common/state'; +import { getBackgroundColor } from 'vs/code/electron-main/theme'; import { dispose, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; export class SharedProcess implements ISharedProcess { @@ -25,15 +26,15 @@ export class SharedProcess implements ISharedProcess { private userEnv: NodeJS.ProcessEnv, @IEnvironmentService private readonly environmentService: IEnvironmentService, @ILifecycleService private readonly lifecycleService: ILifecycleService, - @ILogService private readonly logService: ILogService, - @IThemeMainService private readonly themeMainService: IThemeMainService + @IStateService private readonly stateService: IStateService, + @ILogService private readonly logService: ILogService ) { } @memoize private get _whenReady(): Promise { this.window = new BrowserWindow({ show: false, - backgroundColor: this.themeMainService.getBackgroundColor(), + backgroundColor: getBackgroundColor(this.stateService), webPreferences: { images: false, webaudio: false, diff --git a/src/vs/code/electron-main/theme.ts b/src/vs/code/electron-main/theme.ts new file mode 100644 index 0000000000..4710c45392 --- /dev/null +++ b/src/vs/code/electron-main/theme.ts @@ -0,0 +1,44 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { isWindows, isMacintosh } from 'vs/base/common/platform'; +import { systemPreferences } from 'electron'; +import { IStateService } from 'vs/platform/state/common/state'; + +const DEFAULT_BG_LIGHT = '#FFFFFF'; +const DEFAULT_BG_DARK = '#1E1E1E'; +const DEFAULT_BG_HC_BLACK = '#000000'; + +const THEME_STORAGE_KEY = 'theme'; +const THEME_BG_STORAGE_KEY = 'themeBackground'; + +export function storeBackgroundColor(stateService: IStateService, data: { baseTheme: string, background: string }): void { + stateService.setItem(THEME_STORAGE_KEY, data.baseTheme); + stateService.setItem(THEME_BG_STORAGE_KEY, data.background); +} + +export function getBackgroundColor(stateService: IStateService): string { + if (isWindows && systemPreferences.isInvertedColorScheme()) { + return DEFAULT_BG_HC_BLACK; + } + + let background = stateService.getItem(THEME_BG_STORAGE_KEY, null); + if (!background) { + let baseTheme: string; + if (isWindows && systemPreferences.isInvertedColorScheme()) { + baseTheme = 'hc-black'; + } else { + baseTheme = stateService.getItem(THEME_STORAGE_KEY, 'vs-dark').split(' ')[0]; + } + + background = (baseTheme === 'hc-black') ? DEFAULT_BG_HC_BLACK : (baseTheme === 'vs' ? DEFAULT_BG_LIGHT : DEFAULT_BG_DARK); + } + + if (isMacintosh && background.toUpperCase() === DEFAULT_BG_DARK) { + background = '#171717'; // https://github.com/electron/electron/issues/5150 + } + + return background; +} \ No newline at end of file diff --git a/src/vs/code/electron-main/window.ts b/src/vs/code/electron-main/window.ts index 12e78be10e..99d30e973c 100644 --- a/src/vs/code/electron-main/window.ts +++ b/src/vs/code/electron-main/window.ts @@ -7,6 +7,7 @@ import * as path from 'vs/base/common/path'; import * as objects from 'vs/base/common/objects'; import * as nls from 'vs/nls'; import { URI } from 'vs/base/common/uri'; +import { IStateService } from 'vs/platform/state/common/state'; import { screen, BrowserWindow, systemPreferences, app, TouchBar, nativeImage, Rectangle, Display } from 'electron'; import { IEnvironmentService, ParsedArgs } from 'vs/platform/environment/common/environment'; import { ILogService } from 'vs/platform/log/common/log'; @@ -22,9 +23,9 @@ import { IBackupMainService } from 'vs/platform/backup/common/backup'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import * as perf from 'vs/base/common/performance'; import { resolveMarketplaceHeaders } from 'vs/platform/extensionManagement/node/extensionGalleryService'; -import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService'; -import { endsWith } from 'vs/base/common/strings'; +import { getBackgroundColor } from 'vs/code/electron-main/theme'; import { RunOnceScheduler } from 'vs/base/common/async'; +import { endsWith } from 'vs/base/common/strings'; export interface IWindowCreationOptions { state: IWindowState; @@ -83,7 +84,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { @ILogService private readonly logService: ILogService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IThemeMainService private readonly themeMainService: IThemeMainService, + @IStateService private readonly stateService: IStateService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IBackupMainService private readonly backupMainService: IBackupMainService, ) { @@ -123,7 +124,7 @@ export class CodeWindow extends Disposable implements ICodeWindow { height: this.windowState.height, x: this.windowState.x, y: this.windowState.y, - backgroundColor: this.themeMainService.getBackgroundColor(), + backgroundColor: getBackgroundColor(this.stateService), minWidth: CodeWindow.MIN_WIDTH, minHeight: CodeWindow.MIN_HEIGHT, show: !isFullscreenOrMaximized, @@ -203,6 +204,12 @@ export class CodeWindow extends Disposable implements ICodeWindow { return !!this.config.extensionTestsPath; } + /* + get extensionDevelopmentPaths(): string | string[] | undefined { + return this.config.extensionDevelopmentPath; + } + */ + get config(): IWindowConfiguration { return this.currentConfig; } diff --git a/src/vs/code/electron-main/windows.ts b/src/vs/code/electron-main/windows.ts index 15cb7748cf..9159e6e935 100644 --- a/src/vs/code/electron-main/windows.ts +++ b/src/vs/code/electron-main/windows.ts @@ -15,7 +15,7 @@ import { CodeWindow, defaultWindowState } from 'vs/code/electron-main/window'; import { hasArgs, asArray } from 'vs/platform/environment/node/argv'; import { ipcMain as ipc, screen, BrowserWindow, dialog, systemPreferences, FileFilter } from 'electron'; import { parseLineAndColumnAware } from 'vs/code/node/paths'; -import { ILifecycleService, UnloadReason, LifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; +import { ILifecycleService, UnloadReason, LifecycleService } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService } from 'vs/platform/log/common/log'; import { IWindowSettings, OpenContext, IPath, IWindowConfiguration, INativeOpenDialogOptions, IPathsToWaitFor, IEnterWorkspaceResult, IMessageBoxResult, INewWindowOptions, IURIToOpen, isFileToOpen, isWorkspaceToOpen, isFolderToOpen } from 'vs/platform/windows/common/windows'; @@ -38,8 +38,6 @@ import { getComparisonKey, isEqual, normalizePath, basename as resourcesBasename import { getRemoteAuthority } from 'vs/platform/remote/common/remoteHosts'; import { restoreWindowsState, WindowsStateStorageData, getWindowsStateStoreData } from 'vs/code/electron-main/windowsStateStorage'; import { getWorkspaceIdentifier } from 'vs/platform/workspaces/electron-main/workspacesMainService'; -import { once } from 'vs/base/common/functional'; -import { Disposable } from 'vs/base/common/lifecycle'; const enum WindowError { UNRESPONSIVE = 1, @@ -155,13 +153,15 @@ interface IWorkspacePathToOpen { label?: string; } -export class WindowsManager extends Disposable implements IWindowsMainService { +export class WindowsManager implements IWindowsMainService { _serviceBrand: any; private static readonly windowsStateStorageKey = 'windowsState'; - private static readonly WINDOWS: ICodeWindow[] = []; + private static WINDOWS: ICodeWindow[] = []; + + private initialUserEnv: IProcessEnvironment; private readonly windowsState: IWindowsState; private lastClosedWindowState?: IWindowState; @@ -169,21 +169,20 @@ export class WindowsManager extends Disposable implements IWindowsMainService { private readonly dialogs: Dialogs; private readonly workspacesManager: WorkspacesManager; - private readonly _onWindowReady = this._register(new Emitter()); - readonly onWindowReady: CommonEvent = this._onWindowReady.event; + private _onWindowReady = new Emitter(); + onWindowReady: CommonEvent = this._onWindowReady.event; - private readonly _onWindowClose = this._register(new Emitter()); - readonly onWindowClose: CommonEvent = this._onWindowClose.event; + private _onWindowClose = new Emitter(); + onWindowClose: CommonEvent = this._onWindowClose.event; - private readonly _onWindowLoad = this._register(new Emitter()); - readonly onWindowLoad: CommonEvent = this._onWindowLoad.event; + private _onWindowLoad = new Emitter(); + onWindowLoad: CommonEvent = this._onWindowLoad.event; - private readonly _onWindowsCountChanged = this._register(new Emitter()); - readonly onWindowsCountChanged: CommonEvent = this._onWindowsCountChanged.event; + private _onWindowsCountChanged = new Emitter(); + onWindowsCountChanged: CommonEvent = this._onWindowsCountChanged.event; constructor( private readonly machineId: string, - private readonly initialUserEnv: IProcessEnvironment, @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService, @IEnvironmentService private readonly environmentService: IEnvironmentService, @@ -195,7 +194,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { - super(); const windowsStateStoreData = this.stateService.getItem(WindowsManager.windowsStateStorageKey); this.windowsState = restoreWindowsState(windowsStateStoreData); @@ -205,50 +203,12 @@ export class WindowsManager extends Disposable implements IWindowsMainService { this.dialogs = new Dialogs(stateService, this); this.workspacesManager = new WorkspacesManager(workspacesMainService, backupMainService, this); - - this.lifecycleService.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); - this.lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.setupNativeHelpers()); } - private setupNativeHelpers(): void { - if (isWindows) { + ready(initialUserEnv: IProcessEnvironment): void { + this.initialUserEnv = initialUserEnv; - // Setup Windows mutex - try { - const WindowsMutex = (require.__$__nodeRequire('windows-mutex') as typeof import('windows-mutex')).Mutex; - const mutex = new WindowsMutex(product.win32MutexName); - once(this.lifecycleService.onWillShutdown)(() => mutex.release()); - } catch (e) { - this.logService.error(e); - - if (!this.environmentService.isBuilt) { - this.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-mutex!', - detail: e.toString(), - noLink: true - }); - } - } - - // Dev only: Ensure Windows foreground love module is present - if (!this.environmentService.isBuilt) { - try { - require.__$__nodeRequire('windows-foreground-love'); - } catch (e) { - this.logService.error(e); - - this.showMessageBox({ - title: product.nameLong, - type: 'warning', - message: 'Failed to load windows-foreground-love!', - detail: e.toString(), - noLink: true - }); - } - } - } + this.registerListeners(); } private registerListeners(): void { @@ -583,7 +543,6 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Find suitable window or folder path to open files in const fileToCheck = fileInputs.filesToOpenOrCreate[0] || fileInputs.filesToDiff[0]; - // only look at the windows with correct authority const windows = WindowsManager.WINDOWS.filter(w => w.remoteAuthority === fileInputs!.remoteAuthority); @@ -680,6 +639,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { // Handle folders to open (instructed and to restore) const allFoldersToOpen = arrays.distinct(foldersToOpen, folder => getComparisonKey(folder.folderUri)); // prevent duplicates + if (allFoldersToOpen.length > 0) { // Check for existing instances @@ -753,9 +713,7 @@ export class WindowsManager extends Disposable implements IWindowsMainService { if (fileInputs && !emptyToOpen) { emptyToOpen++; } - const remoteAuthority = fileInputs ? fileInputs.remoteAuthority : (openConfig.cli && openConfig.cli.remote || undefined); - for (let i = 0; i < emptyToOpen; i++) { usedWindows.push(this.openInBrowserWindow({ userEnv: openConfig.userEnv, @@ -1578,13 +1536,14 @@ export class WindowsManager extends Disposable implements IWindowsMainService { return state; } - async reload(win: ICodeWindow, cli?: ParsedArgs): Promise { + reload(win: ICodeWindow, cli?: ParsedArgs): void { // Only reload when the window has not vetoed this - const veto = await this.lifecycleService.unload(win, UnloadReason.RELOAD); - if (!veto) { - win.reload(undefined, cli); - } + this.lifecycleService.unload(win, UnloadReason.RELOAD).then(veto => { + if (!veto) { + win.reload(undefined, cli); + } + }); } closeWorkspace(win: ICodeWindow): void { @@ -1595,10 +1554,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { }); } - async enterWorkspace(win: ICodeWindow, path: URI): Promise { - const result = await this.workspacesManager.enterWorkspace(win, path); - - return result ? this.doEnterWorkspace(win, result) : undefined; + enterWorkspace(win: ICodeWindow, path: URI): Promise { + return this.workspacesManager.enterWorkspace(win, path).then(result => result ? this.doEnterWorkspace(win, result) : undefined); } private doEnterWorkspace(win: ICodeWindow, result: IEnterWorkspaceResult): IEnterWorkspaceResult { @@ -1794,10 +1751,8 @@ export class WindowsManager extends Disposable implements IWindowsMainService { const paths = await this.dialogs.pick({ ...options, pickFolders: true, pickFiles: true, title }); if (paths) { this.sendPickerTelemetry(paths, options.telemetryEventName || 'openFileFolder', options.telemetryExtraData); - const urisToOpen = await Promise.all(paths.map(async path => { - const isDir = await dirExists(path); - - return isDir ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) }; + const urisToOpen = await Promise.all(paths.map(path => { + return dirExists(path).then(isDir => isDir ? { folderUri: URI.file(path) } : { fileUri: URI.file(path) }); })); this.open({ context: OpenContext.DIALOG, @@ -1925,7 +1880,7 @@ class Dialogs { this.noWindowDialogQueue = new Queue(); } - async pick(options: IInternalNativeOpenDialogOptions): Promise { + pick(options: IInternalNativeOpenDialogOptions): Promise { // Ensure dialog options const dialogOptions: Electron.OpenDialogOptions = { @@ -1958,16 +1913,16 @@ class Dialogs { // Show Dialog const focusedWindow = (typeof options.windowId === 'number' ? this.windowsMainService.getWindowById(options.windowId) : undefined) || this.windowsMainService.getFocusedWindow(); - const paths = await this.showOpenDialog(dialogOptions, focusedWindow); - if (paths && paths.length > 0) { + return this.showOpenDialog(dialogOptions, focusedWindow).then(paths => { + if (paths && paths.length > 0) { - // Remember path in storage for next time - this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(paths[0])); + // Remember path in storage for next time + this.stateService.setItem(Dialogs.workingDirPickerStorageKey, dirname(paths[0])); + return paths; + } - return paths; - } - - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check + return undefined; + }); } private getDialogQueue(window?: ICodeWindow): Queue { @@ -2073,26 +2028,28 @@ class WorkspacesManager { private readonly windowsMainService: IWindowsMainService, ) { } - async enterWorkspace(window: ICodeWindow, path: URI): Promise { + enterWorkspace(window: ICodeWindow, path: URI): Promise { if (!window || !window.win || !window.isReady) { - return null; // return early if the window is not ready or disposed + return Promise.resolve(null); // return early if the window is not ready or disposed } - const isValid = await this.isValidTargetWorkspacePath(window, path); - if (!isValid) { - return null; // return early if the workspace is not valid - } + return this.isValidTargetWorkspacePath(window, path).then(isValid => { + if (!isValid) { + return null; // return early if the workspace is not valid + } + const workspaceIdentifier = getWorkspaceIdentifier(path); + return this.doOpenWorkspace(window, workspaceIdentifier); + }); - return this.doOpenWorkspace(window, getWorkspaceIdentifier(path)); } - private async isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { + private isValidTargetWorkspacePath(window: ICodeWindow, path?: URI): Promise { if (!path) { - return true; + return Promise.resolve(true); } if (window.openedWorkspace && isEqual(window.openedWorkspace.configPath, path)) { - return false; // window is already opened on a workspace with that path + return Promise.resolve(false); // window is already opened on a workspace with that path } // Prevent overwriting a workspace that is currently opened in another window @@ -2106,12 +2063,10 @@ class WorkspacesManager { noLink: true }; - await this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()); - - return false; + return this.windowsMainService.showMessageBox(options, this.windowsMainService.getFocusedWindow()).then(() => false); } - return true; // OK + return Promise.resolve(true); // OK } private doOpenWorkspace(window: ICodeWindow, workspace: IWorkspaceIdentifier): IEnterWorkspaceResult { @@ -2135,16 +2090,14 @@ class WorkspacesManager { return { workspace, backupPath }; } + } -function resourceFromURIToOpen(u: IURIToOpen): URI { +function resourceFromURIToOpen(u: IURIToOpen) { if (isWorkspaceToOpen(u)) { return u.workspaceUri; - } - - if (isFolderToOpen(u)) { + } else if (isFolderToOpen(u)) { return u.folderUri; } - return u.fileUri; } \ No newline at end of file diff --git a/src/vs/code/node/cli.ts b/src/vs/code/node/cli.ts index 805e3f3ce6..bf2c6afc32 100644 --- a/src/vs/code/node/cli.ts +++ b/src/vs/code/node/cli.ts @@ -57,7 +57,6 @@ export async function main(argv: string[]): Promise { else if (shouldSpawnCliProcess(args)) { const cli = await new Promise((c, e) => require(['vs/code/node/cliProcessMain'], c, e)); await cli.main(args); - return; } @@ -258,7 +257,7 @@ export async function main(argv: string[]): Promise { addArg(argv, `--prof-startup-prefix`, filenamePrefix); addArg(argv, `--no-cached-data`); - writeFileSync(filenamePrefix, argv.slice(-6).join('|')); + fs.writeFileSync(filenamePrefix, argv.slice(-6).join('|')); processCallbacks.push(async _child => { @@ -330,7 +329,7 @@ export async function main(argv: string[]): Promise { await extHost.stop(); // re-create the marker file to signal that profiling is done - writeFileSync(filenamePrefix, ''); + fs.writeFileSync(filenamePrefix, ''); } catch (e) { console.error('Failed to profile startup. Make sure to quit Code first.'); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index d4ee611708..04c6304e0e 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -31,6 +31,7 @@ import { mkdirp, writeFile } from 'vs/base/node/pfs'; import { getBaseLabel } from 'vs/base/common/labels'; import { IStateService } from 'vs/platform/state/common/state'; import { StateService } from 'vs/platform/state/node/stateService'; +import { createBufferSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ILogService, getLogLevel } from 'vs/platform/log/common/log'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { areSameExtensions, adoptToGalleryExtensionId, getGalleryExtensionId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -40,11 +41,10 @@ import { IExtensionManifest, ExtensionType, isLanguagePackExtension } from 'vs/p import { CancellationToken } from 'vs/base/common/cancellation'; import { LocalizationsService } from 'vs/platform/localizations/node/localizations'; import { Schemas } from 'vs/base/common/network'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; const notFound = (id: string) => localize('notFound', "Extension '{0}' not found.", id); const notInstalled = (id: string) => localize('notInstalled', "Extension '{0}' is not installed.", id); -const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, e.g.: {0}", 'ms-vscode.csharp'); +const useId = localize('useId', "Make sure you use the full extension ID, including the publisher, eg: {0}", 'ms-vscode.csharp'); function getId(manifest: IExtensionManifest, withVersion?: boolean): string { if (withVersion) { @@ -275,22 +275,17 @@ export class Main { const eventPrefix = 'monacoworkbench'; -export async function main(argv: ParsedArgs): Promise { +export function main(argv: ParsedArgs): Promise { const services = new ServiceCollection(); const environmentService = new EnvironmentService(argv, process.execPath); - const logService: ILogService = new SpdLogService('cli', environmentService.logsPath, getLogLevel(environmentService)); + const logService = createBufferSpdLogService('cli', getLogLevel(environmentService), environmentService.logsPath); process.once('exit', () => logService.dispose()); + logService.info('main', argv); - await Promise.all([environmentService.appSettingsHome, environmentService.extensionsPath].map(p => mkdirp(p))); - - const configurationService = new ConfigurationService(environmentService.settingsResource.path); - await configurationService.initialize(); - services.set(IEnvironmentService, environmentService); services.set(ILogService, logService); - services.set(IConfigurationService, configurationService); services.set(IStateService, new SyncDescriptor(StateService)); const instantiationService: IInstantiationService = new InstantiationService(services); @@ -299,37 +294,40 @@ export async function main(argv: ParsedArgs): Promise { const envService = accessor.get(IEnvironmentService); const stateService = accessor.get(IStateService); - const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; + return Promise.all([envService.appSettingsHome, envService.extensionsPath].map(p => mkdirp(p))).then(() => { + const { appRoot, extensionsPath, extensionDevelopmentLocationURI: extensionDevelopmentLocationURI, isBuilt, installSourcePath } = envService; - const services = new ServiceCollection(); - services.set(IRequestService, new SyncDescriptor(RequestService)); - services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); - services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); + const services = new ServiceCollection(); + services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.appSettingsPath])); + services.set(IRequestService, new SyncDescriptor(RequestService)); + services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); + services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); - const appenders: AppInsightsAppender[] = []; - if (isBuilt && !extensionDevelopmentLocationURI && !envService.args['disable-telemetry'] && product.enableTelemetry) { + const appenders: AppInsightsAppender[] = []; + if (isBuilt && !extensionDevelopmentLocationURI && !envService.args['disable-telemetry'] && product.enableTelemetry) { - if (product.aiConfig && product.aiConfig.asimovKey) { - appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, logService)); + if (product.aiConfig && product.aiConfig.asimovKey) { + appenders.push(new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, logService)); + } + + const config: ITelemetryServiceConfig = { + appender: combinedAppender(...appenders), + commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), + piiPaths: [appRoot, extensionsPath] + }; + + services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); + } else { + services.set(ITelemetryService, NullTelemetryService); } - const config: ITelemetryServiceConfig = { - appender: combinedAppender(...appenders), - commonProperties: resolveCommonProperties(product.commit, pkg.version, stateService.getItem('telemetry.machineId'), installSourcePath), - piiPaths: [appRoot, extensionsPath] - }; + const instantiationService2 = instantiationService.createChild(services); + const main = instantiationService2.createInstance(Main); - services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); - } else { - services.set(ITelemetryService, NullTelemetryService); - } - - const instantiationService2 = instantiationService.createChild(services); - const main = instantiationService2.createInstance(Main); - - return main.run(argv).then(() => { - // Dispose the AI adapter so that remaining data gets flushed. - return combinedAppender(...appenders).dispose(); + return main.run(argv).then(() => { + // Dispose the AI adapter so that remaining data gets flushed. + return combinedAppender(...appenders).dispose(); + }); }); }); } \ No newline at end of file diff --git a/src/vs/code/node/shellEnv.ts b/src/vs/code/node/shellEnv.ts index c8eec0c3b4..80ab30eb96 100644 --- a/src/vs/code/node/shellEnv.ts +++ b/src/vs/code/node/shellEnv.ts @@ -8,7 +8,6 @@ import { assign } from 'vs/base/common/objects'; import { generateUuid } from 'vs/base/common/uuid'; import { isWindows } from 'vs/base/common/platform'; import { ILogService } from 'vs/platform/log/common/log'; -import { IEnvironmentService } from 'vs/platform/environment/common/environment'; function getUnixShellEnvironment(logService: ILogService): Promise { const promise = new Promise((resolve, reject) => { @@ -90,12 +89,9 @@ let _shellEnv: Promise; * This should only be done when Code itself is not launched * from within a shell. */ -export function getShellEnvironment(logService: ILogService, environmentService: IEnvironmentService): Promise { +export function getShellEnvironment(logService: ILogService): Promise { if (_shellEnv === undefined) { - if (environmentService.args['disable-user-env-probe']) { - logService.trace('getShellEnvironment: disable-user-env-probe set, skipping'); - _shellEnv = Promise.resolve({}); - } else if (isWindows) { + if (isWindows) { logService.trace('getShellEnvironment: runing on windows, skipping'); _shellEnv = Promise.resolve({}); } else if (process.env['VSCODE_CLI'] === '1') { diff --git a/src/vs/editor/browser/core/editorState.ts b/src/vs/editor/browser/core/editorState.ts index f15229fb1e..923566afae 100644 --- a/src/vs/editor/browser/core/editorState.ts +++ b/src/vs/editor/browser/core/editorState.ts @@ -79,7 +79,7 @@ export class EditorState { * A cancellation token source that cancels when the editor changes as expressed * by the provided flags */ -export class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource implements IDisposable { +export class EditorStateCancellationTokenSource extends EditorKeybindingCancellationTokenSource { private readonly _listener: IDisposable[] = []; @@ -110,7 +110,7 @@ export class EditorStateCancellationTokenSource extends EditorKeybindingCancella /** * A cancellation token source that cancels when the provided model changes */ -export class TextModelCancellationTokenSource extends CancellationTokenSource implements IDisposable { +export class TextModelCancellationTokenSource extends CancellationTokenSource { private _listener: IDisposable; diff --git a/src/vs/editor/browser/view/viewImpl.ts b/src/vs/editor/browser/view/viewImpl.ts index f223361745..32bc7cff95 100644 --- a/src/vs/editor/browser/view/viewImpl.ts +++ b/src/vs/editor/browser/view/viewImpl.ts @@ -132,7 +132,7 @@ export class View extends ViewEventHandler { this._setLayout(); // Pointer handler - this.pointerHandler = this._register(new PointerHandler(this._context, viewController, this.createPointerHandlerHelper())); + this.pointerHandler = new PointerHandler(this._context, viewController, this.createPointerHandlerHelper()); this._register(model.addEventListener((events: viewEvents.ViewEvent[]) => { this.eventDispatcher.emitMany(events); @@ -342,6 +342,8 @@ export class View extends ViewEventHandler { this.eventDispatcher.removeEventHandler(this); this.outgoingEvents.dispose(); + this.pointerHandler.dispose(); + this.viewLines.dispose(); // Destroy view parts diff --git a/src/vs/editor/browser/viewParts/minimap/minimap.ts b/src/vs/editor/browser/viewParts/minimap/minimap.ts index 5b1070b120..98158ce394 100644 --- a/src/vs/editor/browser/viewParts/minimap/minimap.ts +++ b/src/vs/editor/browser/viewParts/minimap/minimap.ts @@ -257,12 +257,7 @@ class MinimapLayout { const computedSliderRatio = (maxMinimapSliderTop) / (scrollHeight - viewportHeight); const sliderTop = (scrollTop * computedSliderRatio); - let extraLinesAtTheBottom = 0; - if (options.scrollBeyondLastLine) { - const expectedViewportLineCount = viewportHeight / lineHeight; - extraLinesAtTheBottom = expectedViewportLineCount; - } - if (minimapLinesFitting >= lineCount + extraLinesAtTheBottom) { + if (minimapLinesFitting >= lineCount) { // All lines fit in the minimap const startLineNumber = 1; const endLineNumber = lineCount; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 3e5f73e511..f00b97775d 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -38,8 +38,7 @@ import { ClassName } from 'vs/editor/common/model/intervalTree'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IModelContentChangedEvent, IModelDecorationsChangedEvent, IModelLanguageChangedEvent, IModelLanguageConfigurationChangedEvent, IModelOptionsChangedEvent } from 'vs/editor/common/model/textModelEvents'; import * as modes from 'vs/editor/common/modes'; -import { editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity } from 'vs/editor/common/view/editorColorRegistry'; -import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorWarningBorder, editorWarningForeground } from 'vs/platform/theme/common/colorRegistry'; +import { editorErrorBorder, editorErrorForeground, editorHintBorder, editorHintForeground, editorInfoBorder, editorInfoForeground, editorUnnecessaryCodeBorder, editorUnnecessaryCodeOpacity, editorWarningBorder, editorWarningForeground } from 'vs/editor/common/view/editorColorRegistry'; import { VerticalRevealType } from 'vs/editor/common/view/viewEvents'; import { IEditorWhitespace } from 'vs/editor/common/viewLayout/whitespaceComputer'; import { ViewModel } from 'vs/editor/common/viewModel/viewModelImpl'; diff --git a/src/vs/editor/browser/widget/diffNavigator.ts b/src/vs/editor/browser/widget/diffNavigator.ts index 5e956dba0f..b08089de4c 100644 --- a/src/vs/editor/browser/widget/diffNavigator.ts +++ b/src/vs/editor/browser/widget/diffNavigator.ts @@ -5,7 +5,7 @@ import * as assert from 'vs/base/common/assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -33,11 +33,12 @@ const defaultOptions: Options = { /** * Create a new diff navigator for the provided diff editor. */ -export class DiffNavigator extends Disposable { +export class DiffNavigator { private readonly _editor: IDiffEditor; private readonly _options: Options; - private readonly _onDidUpdate = this._register(new Emitter()); + private readonly _disposables: IDisposable[]; + private readonly _onDidUpdate = new Emitter(); readonly onDidUpdate: Event = this._onDidUpdate.event; @@ -48,11 +49,11 @@ export class DiffNavigator extends Disposable { private ignoreSelectionChange: boolean; constructor(editor: IDiffEditor, options: Options = {}) { - super(); this._editor = editor; this._options = objects.mixin(options, defaultOptions, false); this.disposed = false; + this._disposables = []; this.nextIdx = -1; this.ranges = []; @@ -60,11 +61,11 @@ export class DiffNavigator extends Disposable { this.revealFirst = Boolean(this._options.alwaysRevealFirst); // hook up to diff editor for diff, disposal, and caret move - this._register(this._editor.onDidDispose(() => this.dispose())); - this._register(this._editor.onDidUpdateDiff(() => this._onDiffUpdated())); + this._disposables.push(this._editor.onDidDispose(() => this.dispose())); + this._disposables.push(this._editor.onDidUpdateDiff(() => this._onDiffUpdated())); if (this._options.followsCaret) { - this._register(this._editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { + this._disposables.push(this._editor.getModifiedEditor().onDidChangeCursorPosition((e: ICursorPositionChangedEvent) => { if (this.ignoreSelectionChange) { return; } @@ -72,7 +73,7 @@ export class DiffNavigator extends Disposable { })); } if (this._options.alwaysRevealFirst) { - this._register(this._editor.getModifiedEditor().onDidChangeModel((e) => { + this._disposables.push(this._editor.getModifiedEditor().onDidChangeModel((e) => { this.revealFirst = true; })); } @@ -215,7 +216,9 @@ export class DiffNavigator extends Disposable { } dispose(): void { - super.dispose(); + dispose(this._disposables); + this._disposables.length = 0; + this._onDidUpdate.dispose(); this.ranges = []; this.disposed = true; } diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 8a561edb93..664f83d281 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -839,7 +839,7 @@ const editorConfiguration: IConfigurationNode = { enumDescriptions: [ nls.localize('editor.gotoLocation.multiple.peek', 'Show peek view of the results (default)'), nls.localize('editor.gotoLocation.multiple.gotoAndPeek', 'Go to the primary result and show a peek view'), - nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and enable peek-less navigation to others') + nls.localize('editor.gotoLocation.multiple.goto', 'Go to the primary result and ignore others') ] }, 'editor.selectionHighlight': { diff --git a/src/vs/editor/common/core/uint.ts b/src/vs/editor/common/core/uint.ts index 4532f4a22f..a91e40a647 100644 --- a/src/vs/editor/common/core/uint.ts +++ b/src/vs/editor/common/core/uint.ts @@ -10,7 +10,7 @@ export class Uint8Matrix { public readonly cols: number; constructor(rows: number, cols: number, defaultValue: number) { - const data = new Uint8Array(rows * cols); + let data = new Uint8Array(rows * cols); for (let i = 0, len = rows * cols; i < len; i++) { data[i] = defaultValue; } @@ -85,8 +85,8 @@ export function toUint32(v: number): number { } export function toUint32Array(arr: number[]): Uint32Array { - const len = arr.length; - const r = new Uint32Array(len); + let len = arr.length; + let r = new Uint32Array(len); for (let i = 0; i < len; i++) { r[i] = toUint32(arr[i]); } diff --git a/src/vs/editor/common/model/indentationGuesser.ts b/src/vs/editor/common/model/indentationGuesser.ts index 884d657d70..e41a7d0bd2 100644 --- a/src/vs/editor/common/model/indentationGuesser.ts +++ b/src/vs/editor/common/model/indentationGuesser.ts @@ -177,26 +177,22 @@ export function guessIndentation(source: ITextBuffer, defaultTabSize: number, de } let tabSize = defaultTabSize; + let tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount); - // Guess tabSize only if inserting spaces... - if (insertSpaces) { - let tabSizeScore = (insertSpaces ? 0 : 0.1 * linesCount); + // console.log("score threshold: " + tabSizeScore); - // console.log("score threshold: " + tabSizeScore); - - ALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => { - let possibleTabSizeScore = spacesDiffCount[possibleTabSize]; - if (possibleTabSizeScore > tabSizeScore) { - tabSizeScore = possibleTabSizeScore; - tabSize = possibleTabSize; - } - }); - - // Let a tabSize of 2 win even if it is not the maximum - // (only in case 4 was guessed) - if (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) { - tabSize = 2; + ALLOWED_TAB_SIZE_GUESSES.forEach((possibleTabSize) => { + let possibleTabSizeScore = spacesDiffCount[possibleTabSize]; + if (possibleTabSizeScore > tabSizeScore) { + tabSizeScore = possibleTabSizeScore; + tabSize = possibleTabSize; } + }); + + // Let a tabSize of 2 win even if it is not the maximum + // (only in case 4 was guessed) + if (tabSize === 4 && spacesDiffCount[4] > 0 && spacesDiffCount[2] > 0 && spacesDiffCount[2] >= spacesDiffCount[4] / 2) { + tabSize = 2; } diff --git a/src/vs/editor/common/modes.ts b/src/vs/editor/common/modes.ts index f42c5fd920..ca1acb961f 100644 --- a/src/vs/editor/common/modes.ts +++ b/src/vs/editor/common/modes.ts @@ -550,10 +550,6 @@ export interface CodeActionContext { trigger: CodeActionTrigger; } -export interface CodeActionList extends IDisposable { - readonly actions: ReadonlyArray; -} - /** * The code action interface defines the contract between extensions and * the [light bulb](https://code.visualstudio.com/docs/editor/editingevolved#_code-action) feature. @@ -563,7 +559,7 @@ export interface CodeActionProvider { /** * Provide commands for the given document and range. */ - provideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult; + provideCodeActions(model: model.ITextModel, range: Range | Selection, context: CodeActionContext, token: CancellationToken): ProviderResult; /** * Optional list of CodeActionKinds that this provider returns. @@ -1004,7 +1000,6 @@ export interface IInplaceReplaceSupportResult { export interface ILink { range: IRange; url?: URI | string; - tooltip?: string; } export interface ILinksList { @@ -1098,6 +1093,7 @@ export interface DocumentColorProvider { } export interface SelectionRange { + kind: string; range: IRange; } @@ -1465,21 +1461,15 @@ export interface IWebviewPanelOptions { readonly retainContextWhenHidden?: boolean; } -export interface CodeLens { +export interface ICodeLensSymbol { range: IRange; id?: string; command?: Command; } - -export interface CodeLensList { - lenses: CodeLens[]; - dispose(): void; -} - export interface CodeLensProvider { onDidChange?: Event; - provideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult; - resolveCodeLens?(model: model.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult; + provideCodeLenses(model: model.ITextModel, token: CancellationToken): ProviderResult; + resolveCodeLens?(model: model.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult; } // --- feature registries ------ diff --git a/src/vs/editor/common/view/editorColorRegistry.ts b/src/vs/editor/common/view/editorColorRegistry.ts index 9fe4195b39..f80df149dd 100644 --- a/src/vs/editor/common/view/editorColorRegistry.ts +++ b/src/vs/editor/common/view/editorColorRegistry.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { Color, RGBA } from 'vs/base/common/color'; -import { activeContrastBorder, editorBackground, editorForeground, registerColor, editorWarningForeground, editorInfoForeground, editorWarningBorder, editorInfoBorder } from 'vs/platform/theme/common/colorRegistry'; +import { activeContrastBorder, editorBackground, editorForeground, registerColor } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; /** @@ -37,14 +37,26 @@ export const editorOverviewRulerBorder = registerColor('editorOverviewRuler.bord export const editorGutter = registerColor('editorGutter.background', { dark: editorBackground, light: editorBackground, hc: editorBackground }, nls.localize('editorGutter', 'Background color of the editor gutter. The gutter contains the glyph margins and the line numbers.')); +export const editorErrorForeground = registerColor('editorError.foreground', { dark: '#ea4646', light: '#d60a0a', hc: null }, nls.localize('errorForeground', 'Foreground color of error squigglies in the editor.')); +export const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hc: Color.fromHex('#E47777').transparent(0.8) }, nls.localize('errorBorder', 'Border color of error squigglies in the editor.')); + +export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#4d9e4d', light: '#117711', hc: null }, nls.localize('warningForeground', 'Foreground color of warning squigglies in the editor.')); +export const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('warningBorder', 'Border color of warning squigglies in the editor.')); + +export const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#008000', light: '#008000', hc: null }, nls.localize('infoForeground', 'Foreground color of info squigglies in the editor.')); +export const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info squigglies in the editor.')); + +export const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hc: null }, nls.localize('hintForeground', 'Foreground color of hint squigglies in the editor.')); +export const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hc: Color.fromHex('#eeeeee').transparent(0.8) }, nls.localize('hintBorder', 'Border color of hint squigglies in the editor.')); + export const editorUnnecessaryCodeBorder = registerColor('editorUnnecessaryCode.border', { dark: null, light: null, hc: Color.fromHex('#fff').transparent(0.8) }, nls.localize('unnecessaryCodeBorder', 'Border color of unnecessary (unused) source code in the editor.')); export const editorUnnecessaryCodeOpacity = registerColor('editorUnnecessaryCode.opacity', { dark: Color.fromHex('#000a'), light: Color.fromHex('#0007'), hc: null }, nls.localize('unnecessaryCodeOpacity', 'Opacity of unnecessary (unused) source code in the editor. For example, "#000000c0" will render the code with 75% opacity. For high contrast themes, use the \'editorUnnecessaryCode.border\' theme color to underline unnecessary code instead of fading it out.')); const rulerRangeDefault = new Color(new RGBA(0, 122, 204, 0.6)); export const overviewRulerRangeHighlight = registerColor('editorOverviewRuler.rangeHighlightForeground', { dark: rulerRangeDefault, light: rulerRangeDefault, hc: rulerRangeDefault }, nls.localize('overviewRulerRangeHighlight', 'Overview ruler marker color for range highlights. The color must not be opaque so as not to hide underlying decorations.'), true); export const overviewRulerError = registerColor('editorOverviewRuler.errorForeground', { dark: new Color(new RGBA(255, 18, 18, 0.7)), light: new Color(new RGBA(255, 18, 18, 0.7)), hc: new Color(new RGBA(255, 50, 50, 1)) }, nls.localize('overviewRuleError', 'Overview ruler marker color for errors.')); -export const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: editorWarningForeground, light: editorWarningForeground, hc: editorWarningBorder }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.')); -export const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: editorInfoForeground, light: editorInfoForeground, hc: editorInfoBorder }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.')); +export const overviewRulerWarning = registerColor('editorOverviewRuler.warningForeground', { dark: new Color(new RGBA(18, 136, 18, 0.7)), light: new Color(new RGBA(18, 136, 18, 0.7)), hc: new Color(new RGBA(50, 255, 50, 1)) }, nls.localize('overviewRuleWarning', 'Overview ruler marker color for warnings.')); +export const overviewRulerInfo = registerColor('editorOverviewRuler.infoForeground', { dark: new Color(new RGBA(18, 18, 136, 0.7)), light: new Color(new RGBA(18, 18, 136, 0.7)), hc: new Color(new RGBA(50, 50, 255, 1)) }, nls.localize('overviewRuleInfo', 'Overview ruler marker color for infos.')); // contains all color rules that used to defined in editor/browser/widget/editor.css registerThemingParticipant((theme, collector) => { diff --git a/src/vs/editor/common/viewModel/splitLinesCollection.ts b/src/vs/editor/common/viewModel/splitLinesCollection.ts index 942a74829b..faf1bd239b 100644 --- a/src/vs/editor/common/viewModel/splitLinesCollection.ts +++ b/src/vs/editor/common/viewModel/splitLinesCollection.ts @@ -13,7 +13,6 @@ import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { PrefixSumComputerWithCache } from 'vs/editor/common/viewModel/prefixSumComputer'; import { ICoordinatesConverter, IOverviewRulerDecorations, ViewLineData } from 'vs/editor/common/viewModel/viewModel'; import { ITheme } from 'vs/platform/theme/common/themeService'; -import { IDisposable } from 'vs/base/common/lifecycle'; export class OutputPosition { _outputPositionBrand: void; @@ -63,9 +62,11 @@ export interface ISplitLine { getViewLineNumberOfModelPosition(deltaLineNumber: number, inputColumn: number): number; } -export interface IViewModelLinesCollection extends IDisposable { +export interface IViewModelLinesCollection { createCoordinatesConverter(): ICoordinatesConverter; + dispose(): void; + setWrappingSettings(wrappingIndent: WrappingIndent, wrappingColumn: number, columnsForFullWidthChar: number): boolean; setTabSize(newTabSize: number): boolean; getHiddenAreas(): Range[]; diff --git a/src/vs/editor/contrib/codeAction/codeAction.ts b/src/vs/editor/contrib/codeAction/codeAction.ts index f9f14c303a..367df28c44 100644 --- a/src/vs/editor/contrib/codeAction/codeAction.ts +++ b/src/vs/editor/contrib/codeAction/codeAction.ts @@ -15,14 +15,8 @@ import { CodeAction, CodeActionContext, CodeActionProviderRegistry, CodeActionTr import { IModelService } from 'vs/editor/common/services/modelService'; import { CodeActionFilter, CodeActionKind, CodeActionTrigger, filtersAction, mayIncludeActionsOfKind } from './codeActionTrigger'; import { TextModelCancellationTokenSource } from 'vs/editor/browser/core/editorState'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; -export interface CodeActionSet extends IDisposable { - readonly actions: readonly CodeAction[]; - readonly hasAutoFix: boolean; -} - -class ManagedCodeActionSet extends Disposable implements CodeActionSet { +export class CodeActionSet { private static codeActionsComparator(a: CodeAction, b: CodeAction): number { if (isNonEmptyArray(a.diagnostics)) { @@ -40,10 +34,8 @@ class ManagedCodeActionSet extends Disposable implements CodeActionSet { public readonly actions: readonly CodeAction[]; - public constructor(actions: readonly CodeAction[], disposables: DisposableStore) { - super(); - this._register(disposables); - this.actions = mergeSort([...actions], ManagedCodeActionSet.codeActionsComparator); + public constructor(actions: readonly CodeAction[]) { + this.actions = mergeSort([...actions], CodeActionSet.codeActionsComparator); } public get hasAutoFix() { @@ -67,14 +59,12 @@ export function getCodeActions( const cts = new TextModelCancellationTokenSource(model, token); const providers = getCodeActionProviders(model, filter); - const disposables = new DisposableStore(); const promises = providers.map(provider => { return Promise.resolve(provider.provideCodeActions(model, rangeOrSelection, codeActionContext, cts.token)).then(providedCodeActions => { - if (cts.token.isCancellationRequested || !providedCodeActions) { + if (cts.token.isCancellationRequested || !Array.isArray(providedCodeActions)) { return []; } - disposables.add(providedCodeActions); - return providedCodeActions.actions.filter(action => action && filtersAction(filter, action)); + return providedCodeActions.filter(action => action && filtersAction(filter, action)); }, (err): CodeAction[] => { if (isPromiseCanceledError(err)) { throw err; @@ -94,7 +84,7 @@ export function getCodeActions( return Promise.all(promises) .then(flatten) - .then(actions => new ManagedCodeActionSet(actions, disposables)) + .then(actions => new CodeActionSet(actions)) .finally(() => { listener.dispose(); cts.dispose(); @@ -116,7 +106,7 @@ function getCodeActionProviders( }); } -registerLanguageCommand('_executeCodeActionProvider', async function (accessor, args): Promise> { +registerLanguageCommand('_executeCodeActionProvider', function (accessor, args): Promise> { const { resource, range, kind } = args; if (!(resource instanceof URI) || !Range.isIRange(range)) { throw illegalArgument(); @@ -127,11 +117,9 @@ registerLanguageCommand('_executeCodeActionProvider', async function (accessor, throw illegalArgument(); } - const codeActionSet = await getCodeActions( + return getCodeActions( model, model.validateRange(range), { type: 'manual', filter: { includeSourceActions: true, kind: kind && kind.value ? new CodeActionKind(kind.value) : undefined } }, - CancellationToken.None); - codeActionSet.dispose(); - return codeActionSet.actions; + CancellationToken.None).then(actions => actions.actions); }); diff --git a/src/vs/editor/contrib/codeAction/codeActionCommands.ts b/src/vs/editor/contrib/codeAction/codeActionCommands.ts index c26c5315dd..697f8979d2 100644 --- a/src/vs/editor/contrib/codeAction/codeActionCommands.ts +++ b/src/vs/editor/contrib/codeAction/codeActionCommands.ts @@ -3,8 +3,9 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { CancelablePromise } from 'vs/base/common/async'; import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, EditorCommand, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; @@ -19,10 +20,10 @@ import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/commo import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { CodeActionModel, SUPPORTED_CODE_ACTIONS, CodeActionsState } from './codeActionModel'; -import { CodeActionAutoApply, CodeActionFilter, CodeActionKind, CodeActionTrigger } from './codeActionTrigger'; -import { CodeActionWidget } from './codeActionWidget'; +import { CodeActionAutoApply, CodeActionFilter, CodeActionKind } from './codeActionTrigger'; +import { CodeActionContextMenu } from './codeActionWidget'; import { LightBulbWidget } from './lightBulbWidget'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -44,15 +45,16 @@ export class QuickFixController extends Disposable implements IEditorContributio private readonly _editor: ICodeEditor; private readonly _model: CodeActionModel; - private readonly _codeActionWidget: CodeActionWidget; + private readonly _codeActionContextMenu: CodeActionContextMenu; private readonly _lightBulbWidget: LightBulbWidget; - private _currentCodeActions: CodeActionSet | undefined; + + private _activeRequest: CancelablePromise | undefined; constructor( editor: ICodeEditor, @IMarkerService markerService: IMarkerService, @IContextKeyService contextKeyService: IContextKeyService, - @ILocalProgressService progressService: ILocalProgressService, + @IProgressService progressService: IProgressService, @IContextMenuService contextMenuService: IContextMenuService, @ICommandService private readonly _commandService: ICommandService, @IKeybindingService private readonly _keybindingService: IKeybindingService, @@ -61,70 +63,58 @@ export class QuickFixController extends Disposable implements IEditorContributio super(); this._editor = editor; - this._model = this._register(new CodeActionModel(this._editor, markerService, contextKeyService, progressService)); - this._codeActionWidget = new CodeActionWidget(editor, contextMenuService, { - onSelectCodeAction: async (action) => { - try { - await this._applyCodeAction(action); - } finally { - // Retrigger - this._trigger({ type: 'auto', filter: {} }); - } - } - }); + this._model = new CodeActionModel(this._editor, markerService, contextKeyService, progressService); + this._codeActionContextMenu = new CodeActionContextMenu(editor, contextMenuService, action => this._onApplyCodeAction(action)); this._lightBulbWidget = this._register(new LightBulbWidget(editor)); this._updateLightBulbTitle(); + this._register(this._codeActionContextMenu.onDidExecuteCodeAction(_ => this._model.trigger({ type: 'auto', filter: {} }))); this._register(this._lightBulbWidget.onClick(this._handleLightBulbSelect, this)); - this._register(this._model.onDidChangeState((newState) => this._onDidChangeCodeActionsState(newState))); + this._register(this._model.onDidChangeState(e => this._onDidChangeCodeActionsState(e))); this._register(this._keybindingService.onDidUpdateKeybindings(this._updateLightBulbTitle, this)); } - dipose() { + public dispose(): void { super.dispose(); - dispose(this._currentCodeActions); + this._model.dispose(); } private _onDidChangeCodeActionsState(newState: CodeActionsState.State): void { - if (newState.type === CodeActionsState.Type.Triggered) { - newState.actions.then(actions => { - dispose(this._currentCodeActions); - this._currentCodeActions = actions; + if (this._activeRequest) { + this._activeRequest.cancel(); + this._activeRequest = undefined; + } - if (!actions.actions.length && newState.trigger.context) { - MessageController.get(this._editor).showMessage(newState.trigger.context.notAvailableMessage, newState.trigger.context.position); - } - }); + if (newState.type === CodeActionsState.Type.Triggered) { + this._activeRequest = newState.actions; if (newState.trigger.filter && newState.trigger.filter.kind) { // Triggered for specific scope - newState.actions.then(codeActions => { - if (codeActions.actions.length > 0) { + newState.actions.then(fixes => { + if (fixes.actions.length > 0) { // Apply if we only have one action or requested autoApply - if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && codeActions.actions.length === 1)) { - this._applyCodeAction(codeActions.actions[0]); + if (newState.trigger.autoApply === CodeActionAutoApply.First || (newState.trigger.autoApply === CodeActionAutoApply.IfSingle && fixes.actions.length === 1)) { + this._onApplyCodeAction(fixes.actions[0]); return; } } - this._codeActionWidget.show(newState.actions, newState.position); + this._codeActionContextMenu.show(newState.actions, newState.position); }).catch(onUnexpectedError); } else if (newState.trigger.type === 'manual') { - this._codeActionWidget.show(newState.actions, newState.position); + this._codeActionContextMenu.show(newState.actions, newState.position); } else { // auto magically triggered // * update an existing list of code actions // * manage light bulb - if (this._codeActionWidget.isVisible) { - this._codeActionWidget.show(newState.actions, newState.position); + if (this._codeActionContextMenu.isVisible) { + this._codeActionContextMenu.show(newState.actions, newState.position); } else { this._lightBulbWidget.tryShow(newState); } } } else { - dispose(this._currentCodeActions); - this._currentCodeActions = undefined; this._lightBulbWidget.hide(); } } @@ -133,26 +123,12 @@ export class QuickFixController extends Disposable implements IEditorContributio return QuickFixController.ID; } - public manualTriggerAtCurrentPosition( - notAvailableMessage: string, - filter?: CodeActionFilter, - autoApply?: CodeActionAutoApply - ): void { - if (!this._editor.hasModel()) { - return; - } - - MessageController.get(this._editor).closeMessage(); - const triggerPosition = this._editor.getPosition(); - this._trigger({ type: 'manual', filter, autoApply, context: { notAvailableMessage, position: triggerPosition } }); - } - - private _trigger(trigger: CodeActionTrigger) { - return this._model.trigger(trigger); - } - private _handleLightBulbSelect(e: { x: number, y: number, state: CodeActionsState.Triggered }): void { - this._codeActionWidget.show(e.state.actions, e); + this._codeActionContextMenu.show(e.state.actions, e); + } + + public triggerFromEditorSelection(filter?: CodeActionFilter, autoApply?: CodeActionAutoApply): Promise { + return this._model.trigger({ type: 'manual', filter, autoApply }); } private _updateLightBulbTitle(): void { @@ -166,7 +142,7 @@ export class QuickFixController extends Disposable implements IEditorContributio this._lightBulbWidget.title = title; } - private _applyCodeAction(action: CodeAction): Promise { + private _onApplyCodeAction(action: CodeAction): Promise { return applyCodeAction(action, this._bulkEditService, this._commandService, this._editor); } } @@ -185,18 +161,28 @@ export async function applyCodeAction( } } -function triggerCodeActionsForEditorSelection( +function showCodeActionsForEditorSelection( editor: ICodeEditor, notAvailableMessage: string, - filter: CodeActionFilter | undefined, - autoApply: CodeActionAutoApply | undefined -): void { - if (editor.hasModel()) { - const controller = QuickFixController.get(editor); - if (controller) { - controller.manualTriggerAtCurrentPosition(notAvailableMessage, filter, autoApply); - } + filter?: CodeActionFilter, + autoApply?: CodeActionAutoApply +) { + if (!editor.hasModel()) { + return; } + + const controller = QuickFixController.get(editor); + if (!controller) { + return; + } + + MessageController.get(editor).closeMessage(); + const pos = editor.getPosition(); + controller.triggerFromEditorSelection(filter, autoApply).then(codeActions => { + if (!codeActions || !codeActions.actions.length) { + MessageController.get(editor).showMessage(notAvailableMessage, pos); + } + }); } export class QuickFixAction extends EditorAction { @@ -218,7 +204,7 @@ export class QuickFixAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), undefined, undefined); + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available")); } } @@ -298,7 +284,7 @@ export class CodeActionCommand extends EditorCommand { kind: CodeActionKind.Empty, apply: CodeActionAutoApply.IfSingle, }); - return triggerCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.quickFix.noneMessage', "No code actions available"), { kind: args.kind, includeSourceActions: true, @@ -361,7 +347,7 @@ export class RefactorAction extends EditorAction { kind: CodeActionKind.Refactor, apply: CodeActionAutoApply.Never }); - return triggerCodeActionsForEditorSelection(editor, + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.refactor.noneMessage', "No refactorings available"), { kind: CodeActionKind.Refactor.contains(args.kind) ? args.kind : CodeActionKind.Empty, @@ -416,7 +402,7 @@ export class SourceAction extends EditorAction { kind: CodeActionKind.Source, apply: CodeActionAutoApply.Never }); - return triggerCodeActionsForEditorSelection(editor, + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.source.noneMessage', "No source actions available"), { kind: CodeActionKind.Source.contains(args.kind) ? args.kind : CodeActionKind.Empty, @@ -448,7 +434,7 @@ export class OrganizeImportsAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return triggerCodeActionsForEditorSelection(editor, + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.organize.noneMessage', "No organize imports action available"), { kind: CodeActionKind.SourceOrganizeImports, includeSourceActions: true }, CodeActionAutoApply.IfSingle); @@ -471,7 +457,7 @@ export class FixAllAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return triggerCodeActionsForEditorSelection(editor, + return showCodeActionsForEditorSelection(editor, nls.localize('fixAll.noneMessage', "No fix all action available"), { kind: CodeActionKind.SourceFixAll, includeSourceActions: true }, CodeActionAutoApply.IfSingle); @@ -502,7 +488,7 @@ export class AutoFixAction extends EditorAction { } public run(_accessor: ServicesAccessor, editor: ICodeEditor): void { - return triggerCodeActionsForEditorSelection(editor, + return showCodeActionsForEditorSelection(editor, nls.localize('editor.action.autoFix.noneMessage', "No auto fixes available"), { kind: CodeActionKind.QuickFix, diff --git a/src/vs/editor/contrib/codeAction/codeActionModel.ts b/src/vs/editor/contrib/codeAction/codeActionModel.ts index e4d714d589..fff21ce6b8 100644 --- a/src/vs/editor/contrib/codeAction/codeActionModel.ts +++ b/src/vs/editor/contrib/codeAction/codeActionModel.ts @@ -4,8 +4,8 @@ *--------------------------------------------------------------------------------------------*/ import { CancelablePromise, createCancelablePromise, TimeoutTimer } from 'vs/base/common/async'; -import { Emitter } from 'vs/base/common/event'; -import { dispose, Disposable } from 'vs/base/common/lifecycle'; +import { Emitter, Event } from 'vs/base/common/event'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; @@ -14,34 +14,36 @@ import { Selection } from 'vs/editor/common/core/selection'; import { CodeActionProviderRegistry } from 'vs/editor/common/modes'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IMarkerService } from 'vs/platform/markers/common/markers'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { getCodeActions, CodeActionSet } from './codeAction'; import { CodeActionTrigger } from './codeActionTrigger'; export const SUPPORTED_CODE_ACTIONS = new RawContextKey('supportedCodeAction', ''); -export type TriggeredCodeAction = undefined | { - readonly selection: Selection; - readonly trigger: CodeActionTrigger; - readonly position: Position; -}; +export class CodeActionOracle { -class CodeActionOracle extends Disposable { - - private readonly _autoTriggerTimer = this._register(new TimeoutTimer()); + private _disposables: IDisposable[] = []; + private readonly _autoTriggerTimer = new TimeoutTimer(); constructor( private readonly _editor: ICodeEditor, private readonly _markerService: IMarkerService, - private readonly _signalChange: (triggered: TriggeredCodeAction) => void, + private readonly _signalChange: (newState: CodeActionsState.State) => void, private readonly _delay: number = 250, + private readonly _progressService?: IProgressService, ) { - super(); - this._register(this._markerService.onMarkerChanged(e => this._onMarkerChanges(e))); - this._register(this._editor.onDidChangeCursorPosition(() => this._onCursorChange())); + this._disposables.push( + this._markerService.onMarkerChanged(e => this._onMarkerChanges(e)), + this._editor.onDidChangeCursorPosition(() => this._onCursorChange()), + ); } - public trigger(trigger: CodeActionTrigger): TriggeredCodeAction { + dispose(): void { + this._disposables = dispose(this._disposables); + this._autoTriggerTimer.cancel(); + } + + trigger(trigger: CodeActionTrigger) { const selection = this._getRangeOfSelectionUnlessWhitespaceEnclosed(trigger); return this._createEventAndSignalChange(trigger, selection); } @@ -110,24 +112,35 @@ class CodeActionOracle extends Disposable { return selection ? selection : undefined; } - private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): TriggeredCodeAction { - const model = this._editor.getModel(); - if (!selection || !model) { + private _createEventAndSignalChange(trigger: CodeActionTrigger, selection: Selection | undefined): Promise { + if (!selection) { // cancel - this._signalChange(undefined); - return undefined; + this._signalChange(CodeActionsState.Empty); + return Promise.resolve(undefined); + } else { + const model = this._editor.getModel(); + if (!model) { + // cancel + this._signalChange(CodeActionsState.Empty); + return Promise.resolve(undefined); + } + + const markerRange = this._getRangeOfMarker(selection); + const position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition(); + const actions = createCancelablePromise(token => getCodeActions(model, selection, trigger, token)); + + if (this._progressService && trigger.type === 'manual') { + this._progressService.showWhile(actions, 250); + } + + this._signalChange(new CodeActionsState.Triggered( + trigger, + selection, + position, + actions + )); + return actions; } - - const markerRange = this._getRangeOfMarker(selection); - const position = markerRange ? markerRange.getStartPosition() : selection.getStartPosition(); - - const e: TriggeredCodeAction = { - trigger, - selection, - position - }; - this._signalChange(e); - return e; } } @@ -154,35 +167,36 @@ export namespace CodeActionsState { export type State = typeof Empty | Triggered; } -export class CodeActionModel extends Disposable { +export class CodeActionModel { private _codeActionOracle?: CodeActionOracle; private _state: CodeActionsState.State = CodeActionsState.Empty; + private _onDidChangeState = new Emitter(); + private _disposables: IDisposable[] = []; private readonly _supportedCodeActions: IContextKey; - private readonly _onDidChangeState = this._register(new Emitter()); - public readonly onDidChangeState = this._onDidChangeState.event; - constructor( private readonly _editor: ICodeEditor, private readonly _markerService: IMarkerService, contextKeyService: IContextKeyService, - private readonly _progressService?: ILocalProgressService + private readonly _progressService: IProgressService ) { - super(); this._supportedCodeActions = SUPPORTED_CODE_ACTIONS.bindTo(contextKeyService); - this._register(this._editor.onDidChangeModel(() => this._update())); - this._register(this._editor.onDidChangeModelLanguage(() => this._update())); - this._register(CodeActionProviderRegistry.onDidChange(() => this._update())); + this._disposables.push(this._editor.onDidChangeModel(() => this._update())); + this._disposables.push(this._editor.onDidChangeModelLanguage(() => this._update())); + this._disposables.push(CodeActionProviderRegistry.onDidChange(() => this._update())); this._update(); } dispose(): void { - super.dispose(); + this._disposables = dispose(this._disposables); dispose(this._codeActionOracle); - this.setState(CodeActionsState.Empty, true); + } + + get onDidChangeState(): Event { + return this._onDidChangeState.event; } private _update(): void { @@ -191,6 +205,9 @@ export class CodeActionModel extends Disposable { this._codeActionOracle = undefined; } + if (this._state.type === CodeActionsState.Type.Triggered) { + this._state.actions.cancel(); + } this.setState(CodeActionsState.Empty); const model = this._editor.getModel(); @@ -207,46 +224,25 @@ export class CodeActionModel extends Disposable { this._supportedCodeActions.set(supportedActions.join(' ')); - this._codeActionOracle = new CodeActionOracle(this._editor, this._markerService, trigger => { - if (!trigger) { - this.setState(CodeActionsState.Empty); - return; - } - - const actions = createCancelablePromise(token => getCodeActions(model, trigger.selection, trigger.trigger, token)); - if (this._progressService && trigger.trigger.type === 'manual') { - this._progressService.showWhile(actions, 250); - } - - this.setState(new CodeActionsState.Triggered(trigger.trigger, trigger.selection, trigger.position, actions)); - - }, undefined); + this._codeActionOracle = new CodeActionOracle(this._editor, this._markerService, newState => this.setState(newState), undefined, this._progressService); this._codeActionOracle.trigger({ type: 'auto' }); } else { this._supportedCodeActions.reset(); } } - public trigger(trigger: CodeActionTrigger) { + public trigger(trigger: CodeActionTrigger): Promise { if (this._codeActionOracle) { - this._codeActionOracle.trigger(trigger); + return this._codeActionOracle.trigger(trigger); } + return Promise.resolve(undefined); } - private setState(newState: CodeActionsState.State, skipNotify?: boolean) { + private setState(newState: CodeActionsState.State) { if (newState === this._state) { return; } - - // Cancel old request - if (this._state.type === CodeActionsState.Type.Triggered) { - this._state.actions.cancel(); - } - this._state = newState; - - if (!skipNotify) { - this._onDidChangeState.fire(newState); - } + this._onDidChangeState.fire(newState); } } diff --git a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts index 382a4bea1a..c641c9ce13 100644 --- a/src/vs/editor/contrib/codeAction/codeActionTrigger.ts +++ b/src/vs/editor/contrib/codeAction/codeActionTrigger.ts @@ -5,7 +5,6 @@ import { startsWith } from 'vs/base/common/strings'; import { CodeAction } from 'vs/editor/common/modes'; -import { Position } from 'vs/editor/common/core/position'; export class CodeActionKind { private static readonly sep = '.'; @@ -91,8 +90,4 @@ export interface CodeActionTrigger { readonly type: 'auto' | 'manual'; readonly filter?: CodeActionFilter; readonly autoApply?: CodeActionAutoApply; - readonly context?: { - readonly notAvailableMessage: string; - readonly position: Position; - }; } \ No newline at end of file diff --git a/src/vs/editor/contrib/codeAction/codeActionWidget.ts b/src/vs/editor/contrib/codeAction/codeActionWidget.ts index 709a16cdb4..8a7c0ea9eb 100644 --- a/src/vs/editor/contrib/codeAction/codeActionWidget.ts +++ b/src/vs/editor/contrib/codeAction/codeActionWidget.ts @@ -6,6 +6,7 @@ import { getDomNodePagePosition } from 'vs/base/browser/dom'; import { Action } from 'vs/base/common/actions'; import { canceled } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -13,32 +14,25 @@ import { CodeAction } from 'vs/editor/common/modes'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { CodeActionSet } from 'vs/editor/contrib/codeAction/codeAction'; -interface CodeActionWidgetDelegate { - onSelectCodeAction: (action: CodeAction) => Promise; -} - -export class CodeActionWidget { +export class CodeActionContextMenu { private _visible: boolean; + private readonly _onDidExecuteCodeAction = new Emitter(); + public readonly onDidExecuteCodeAction: Event = this._onDidExecuteCodeAction.event; + constructor( private readonly _editor: ICodeEditor, private readonly _contextMenuService: IContextMenuService, - private readonly _delegate: CodeActionWidgetDelegate + private readonly _onApplyCodeAction: (action: CodeAction) => Promise ) { } - public async show(actionsToShow: Promise, at?: { x: number; y: number } | Position): Promise { + async show(actionsToShow: Promise, at?: { x: number; y: number } | Position): Promise { const codeActions = await actionsToShow; - if (!codeActions.actions.length) { - this._visible = false; - return; - } if (!this._editor.getDomNode()) { // cancel when editor went off-dom - this._visible = false; return Promise.reject(canceled()); } - this._visible = true; const actions = codeActions.actions.map(action => this.codeActionToAction(action)); this._contextMenuService.showContextMenu({ @@ -60,7 +54,9 @@ export class CodeActionWidget { private codeActionToAction(action: CodeAction): Action { const id = action.command ? action.command.id : action.title; const title = action.title; - return new Action(id, title, undefined, true, () => this._delegate.onSelectCodeAction(action)); + return new Action(id, title, undefined, true, () => + this._onApplyCodeAction(action) + .finally(() => this._onDidExecuteCodeAction.fire(undefined))); } get isVisible(): boolean { diff --git a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts index 8954d19200..41d45f8bb1 100644 --- a/src/vs/editor/contrib/codeAction/lightBulbWidget.ts +++ b/src/vs/editor/contrib/codeAction/lightBulbWidget.ts @@ -45,14 +45,13 @@ export class LightBulbWidget extends Disposable implements IContentWidget { this._futureFixes.cancel(); } })); - this._register(dom.addStandardDisposableListener(this._domNode, 'mousedown', e => { + this._register(dom.addStandardDisposableListener(this._domNode, 'click', e => { if (this._state.type !== CodeActionsState.Type.Triggered) { return; } // Make sure that focus / cursor location is not lost when clicking widget icon this._editor.focus(); - dom.EventHelper.stop(e, true); // a bit of extra work to make sure the menu // doesn't cover the line-text const { top, height } = dom.getDomNodePagePosition(this._domNode); @@ -107,8 +106,9 @@ export class LightBulbWidget extends Disposable implements IContentWidget { return this._position; } - tryShow(newState: CodeActionsState.Triggered) { - if (this._position && (!newState.position || this._position.position && this._position.position.lineNumber !== newState.position.lineNumber)) { + tryShow(newState: CodeActionsState.State) { + + if (newState.type !== CodeActionsState.Type.Triggered || this._position && (!newState.position || this._position.position && this._position.position.lineNumber !== newState.position.lineNumber)) { // hide when getting a 'hide'-request or when currently // showing on another line this.hide(); @@ -121,6 +121,10 @@ export class LightBulbWidget extends Disposable implements IContentWidget { const { token } = this._futureFixes; this._state = newState; + if (this._state.type === CodeActionsState.Empty.type) { + return; + } + const selection = this._state.rangeOrSelection; this._state.actions.then(fixes => { if (!token.isCancellationRequested && fixes.actions.length > 0 && selection) { diff --git a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts index 3ed337306f..aaaca49740 100644 --- a/src/vs/editor/contrib/codeAction/test/codeAction.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeAction.test.ts @@ -3,34 +3,22 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { Range } from 'vs/editor/common/core/range'; import { TextModel } from 'vs/editor/common/model/textModel'; -import * as modes from 'vs/editor/common/modes'; +import { CodeAction, CodeActionContext, CodeActionProvider, CodeActionProviderRegistry, Command, LanguageIdentifier, ResourceTextEdit, WorkspaceEdit } from 'vs/editor/common/modes'; import { getCodeActions } from 'vs/editor/contrib/codeAction/codeAction'; import { CodeActionKind } from 'vs/editor/contrib/codeAction/codeActionTrigger'; import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { CancellationToken } from 'vs/base/common/cancellation'; -function staticCodeActionProvider(...actions: modes.CodeAction[]): modes.CodeActionProvider { - return new class implements modes.CodeActionProvider { - provideCodeActions(): modes.CodeActionList { - return { - actions: actions, - dispose: () => { } - }; - } - }; -} - - suite('CodeAction', () => { - let langId = new modes.LanguageIdentifier('fooLang', 17); + let langId = new LanguageIdentifier('fooLang', 17); let uri = URI.parse('untitled:path'); let model: TextModel; - const disposables = new DisposableStore(); + let disposables: IDisposable[] = []; let testData = { diagnostics: { abc: { @@ -58,7 +46,7 @@ suite('CodeAction', () => { }, command: { abc: { - command: new class implements modes.Command { + command: new class implements Command { id: '1'; title: 'abc'; }, @@ -68,8 +56,8 @@ suite('CodeAction', () => { spelling: { bcd: { diagnostics: [], - edit: new class implements modes.WorkspaceEdit { - edits: modes.ResourceTextEdit[]; + edit: new class implements WorkspaceEdit { + edits: ResourceTextEdit[]; }, title: 'abc' } @@ -91,27 +79,30 @@ suite('CodeAction', () => { }; setup(function () { - disposables.clear(); model = TextModel.createFromString('test1\ntest2\ntest3', undefined, langId, uri); - disposables.add(model); + disposables = [model]; }); teardown(function () { - disposables.clear(); + dispose(disposables); }); test('CodeActions are sorted by type, #38623', async function () { - const provider = staticCodeActionProvider( - testData.command.abc, - testData.diagnostics.bcd, - testData.spelling.bcd, - testData.tsLint.bcd, - testData.tsLint.abc, - testData.diagnostics.abc - ); + const provider = new class implements CodeActionProvider { + provideCodeActions() { + return [ + testData.command.abc, + testData.diagnostics.bcd, + testData.spelling.bcd, + testData.tsLint.bcd, + testData.tsLint.abc, + testData.diagnostics.abc + ]; + } + }; - disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); const expected = [ // CodeActions with a diagnostics array are shown first ordered by diagnostics.message @@ -131,13 +122,17 @@ suite('CodeAction', () => { }); test('getCodeActions should filter by scope', async function () { - const provider = staticCodeActionProvider( - { title: 'a', kind: 'a' }, - { title: 'b', kind: 'b' }, - { title: 'a.b', kind: 'a.b' } - ); + const provider = new class implements CodeActionProvider { + provideCodeActions(): CodeAction[] { + return [ + { title: 'a', kind: 'a' }, + { title: 'b', kind: 'b' }, + { title: 'a.b', kind: 'a.b' } + ]; + } + }; - disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); { const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); @@ -159,18 +154,15 @@ suite('CodeAction', () => { }); test('getCodeActions should forward requested scope to providers', async function () { - const provider = new class implements modes.CodeActionProvider { - provideCodeActions(_model: any, _range: Range, context: modes.CodeActionContext, _token: any): modes.CodeActionList { - return { - actions: [ - { title: context.only || '', kind: context.only } - ], - dispose: () => { } - }; + const provider = new class implements CodeActionProvider { + provideCodeActions(_model: any, _range: Range, context: CodeActionContext, _token: any): CodeAction[] { + return [ + { title: context.only || '', kind: context.only } + ]; } }; - disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', filter: { kind: new CodeActionKind('a') } }, CancellationToken.None); assert.equal(actions.length, 1); @@ -178,12 +170,16 @@ suite('CodeAction', () => { }); test('getCodeActions should not return source code action by default', async function () { - const provider = staticCodeActionProvider( - { title: 'a', kind: CodeActionKind.Source.value }, - { title: 'b', kind: 'b' } - ); + const provider = new class implements CodeActionProvider { + provideCodeActions(): CodeAction[] { + return [ + { title: 'a', kind: CodeActionKind.Source.value }, + { title: 'b', kind: 'b' } + ]; + } + }; - disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); { const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto' }, CancellationToken.None); @@ -200,16 +196,16 @@ suite('CodeAction', () => { test('getCodeActions should not invoke code action providers filtered out by providedCodeActionKinds', async function () { let wasInvoked = false; - const provider = new class implements modes.CodeActionProvider { - provideCodeActions(): modes.CodeActionList { + const provider = new class implements CodeActionProvider { + provideCodeActions() { wasInvoked = true; - return { actions: [], dispose: () => { } }; + return []; } providedCodeActionKinds = [CodeActionKind.Refactor.value]; }; - disposables.add(modes.CodeActionProviderRegistry.register('fooLang', provider)); + disposables.push(CodeActionProviderRegistry.register('fooLang', provider)); const { actions } = await getCodeActions(model, new Range(1, 1, 2, 1), { type: 'auto', diff --git a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts index 59b98899d9..a5bef22904 100644 --- a/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts +++ b/src/vs/editor/contrib/codeAction/test/codeActionModel.test.ts @@ -4,38 +4,32 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Selection } from 'vs/editor/common/core/selection'; import { TextModel } from 'vs/editor/common/model/textModel'; -import * as modes from 'vs/editor/common/modes'; -import { CodeActionModel, CodeActionsState } from 'vs/editor/contrib/codeAction/codeActionModel'; +import { CodeActionProviderRegistry, LanguageIdentifier } from 'vs/editor/common/modes'; +import { CodeActionOracle, CodeActionsState } from 'vs/editor/contrib/codeAction/codeActionModel'; import { createTestCodeEditor } from 'vs/editor/test/browser/testCodeEditor'; -import { MockContextKeyService } from 'vs/platform/keybinding/test/common/mockKeybindingService'; import { MarkerService } from 'vs/platform/markers/common/markerService'; const testProvider = { - provideCodeActions(): modes.CodeActionList { - return { - actions: [ - { title: 'test', command: { id: 'test-command', title: 'test', arguments: [] } } - ], - dispose() { /* noop*/ } - }; + provideCodeActions() { + return [{ id: 'test-command', title: 'test', arguments: [] }]; } }; -suite('CodeActionModel', () => { +suite('CodeAction', () => { - const languageIdentifier = new modes.LanguageIdentifier('foo-lang', 3); + const languageIdentifier = new LanguageIdentifier('foo-lang', 3); let uri = URI.parse('untitled:path'); let model: TextModel; let markerService: MarkerService; let editor: ICodeEditor; - const disposables = new DisposableStore(); + let disposables: IDisposable[]; setup(() => { - disposables.clear(); + disposables = []; markerService = new MarkerService(); model = TextModel.createFromString('foobar foo bar\nfarboo far boo', undefined, languageIdentifier, uri); editor = createTestCodeEditor({ model: model }); @@ -43,28 +37,26 @@ suite('CodeActionModel', () => { }); teardown(() => { - disposables.clear(); + dispose(disposables); editor.dispose(); model.dispose(); markerService.dispose(); }); test('Orcale -> marker added', done => { - const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.add(reg); + const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.push(reg); - const contextKeys = new MockContextKeyService(); - const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { - model.dispose(); + oracle.dispose(); assert.equal(fixes.actions.length, 1); done(); }, done); - })); + }); // start here markerService.changeOne('fake', uri, [{ @@ -78,8 +70,8 @@ suite('CodeActionModel', () => { }); test('Orcale -> position changed', () => { - const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.add(reg); + const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.push(reg); markerService.changeOne('fake', uri, [{ startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6, @@ -92,29 +84,28 @@ suite('CodeActionModel', () => { editor.setPosition({ lineNumber: 2, column: 1 }); return new Promise((resolve, reject) => { - const contextKeys = new MockContextKeyService(); - const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + + const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); assert.ok(e.actions); e.actions.then(fixes => { - model.dispose(); + oracle.dispose(); assert.equal(fixes.actions.length, 1); resolve(undefined); }, reject); - })); + }); // start here editor.setPosition({ lineNumber: 1, column: 1 }); }); }); test('Lightbulb is in the wrong place, #29933', async function () { - const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, { - provideCodeActions(_doc, _range): modes.CodeActionList { - return { actions: [], dispose() { /* noop*/ } }; + const reg = CodeActionProviderRegistry.register(languageIdentifier.language, { + provideCodeActions(_doc, _range) { + return []; } }); - disposables.add(reg); + disposables.push(reg); editor.getModel()!.setValue('// @ts-check\n2\ncon\n'); @@ -128,9 +119,8 @@ suite('CodeActionModel', () => { // case 1 - drag selection over multiple lines -> range of enclosed marker, position or marker await new Promise(resolve => { - const contextKeys = new MockContextKeyService(); - const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + + let oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); const selection = e.rangeOrSelection; assert.deepEqual(selection.selectionStartLineNumber, 1); @@ -138,32 +128,31 @@ suite('CodeActionModel', () => { assert.deepEqual(selection.endLineNumber, 4); assert.deepEqual(selection.endColumn, 1); assert.deepEqual(e.position, { lineNumber: 3, column: 1 }); - model.dispose(); + + oracle.dispose(); resolve(undefined); - }, 5)); + }, 5); editor.setSelection({ startLineNumber: 1, startColumn: 1, endLineNumber: 4, endColumn: 1 }); }); }); test('Orcale -> should only auto trigger once for cursor and marker update right after each other', done => { - const reg = modes.CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); - disposables.add(reg); + const reg = CodeActionProviderRegistry.register(languageIdentifier.language, testProvider); + disposables.push(reg); let triggerCount = 0; - const contextKeys = new MockContextKeyService(); - const model = disposables.add(new CodeActionModel(editor, markerService, contextKeys, undefined)); - disposables.add(model.onDidChangeState((e: CodeActionsState.Triggered) => { + const oracle = new CodeActionOracle(editor, markerService, (e: CodeActionsState.Triggered) => { assert.equal(e.trigger.type, 'auto'); ++triggerCount; // give time for second trigger before completing test setTimeout(() => { - model.dispose(); + oracle.dispose(); assert.strictEqual(triggerCount, 1); done(); }, 50); - }, 5 /*delay*/)); + }, 5 /*delay*/); markerService.changeOne('fake', uri, [{ startLineNumber: 1, startColumn: 1, endLineNumber: 1, endColumn: 6, diff --git a/src/vs/editor/contrib/codelens/codeLensCache.ts b/src/vs/editor/contrib/codelens/codeLensCache.ts index ed11e7d70e..b23eb35037 100644 --- a/src/vs/editor/contrib/codelens/codeLensCache.ts +++ b/src/vs/editor/contrib/codelens/codeLensCache.ts @@ -6,19 +6,18 @@ import { ITextModel } from 'vs/editor/common/model'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { CodeLensModel } from 'vs/editor/contrib/codelens/codelens'; +import { ICodeLensData } from 'vs/editor/contrib/codelens/codelens'; import { LRUCache, values } from 'vs/base/common/map'; -import { CodeLensProvider, CodeLensList, CodeLens } from 'vs/editor/common/modes'; +import { ICodeLensSymbol, CodeLensProvider } from 'vs/editor/common/modes'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { Range } from 'vs/editor/common/core/range'; -import { runWhenIdle } from 'vs/base/common/async'; export const ICodeLensCache = createDecorator('ICodeLensCache'); export interface ICodeLensCache { _serviceBrand: any; - put(model: ITextModel, data: CodeLensModel): void; - get(model: ITextModel): CodeLensModel | undefined; + put(model: ITextModel, data: ICodeLensData[]): void; + get(model: ITextModel): ICodeLensData[] | undefined; delete(model: ITextModel): void; } @@ -31,7 +30,7 @@ class CacheItem { constructor( readonly lineCount: number, - readonly data: CodeLensModel + readonly data: ICodeLensData[] ) { } } @@ -40,7 +39,7 @@ export class CodeLensCache implements ICodeLensCache { _serviceBrand: any; private readonly _fakeProvider = new class implements CodeLensProvider { - provideCodeLenses(): CodeLensList { + provideCodeLenses(): ICodeLensSymbol[] { throw new Error('not supported'); } }; @@ -49,12 +48,9 @@ export class CodeLensCache implements ICodeLensCache { constructor(@IStorageService storageService: IStorageService) { - // remove old data - const oldkey = 'codelens/cache'; - runWhenIdle(() => storageService.remove(oldkey, StorageScope.WORKSPACE)); + const key = 'codelens/cache'; // restore lens data on start - const key = 'codelens/cache2'; const raw = storageService.get(key, StorageScope.WORKSPACE, '{}'); this._deserialize(raw); @@ -65,12 +61,13 @@ export class CodeLensCache implements ICodeLensCache { }); } - put(model: ITextModel, data: CodeLensModel): void { - - const lensModel = new CodeLensModel(); - lensModel.add({ lenses: data.lenses.map(v => v.symbol), dispose() { } }, this._fakeProvider); - - const item = new CacheItem(model.getLineCount(), lensModel); + put(model: ITextModel, data: ICodeLensData[]): void { + const item = new CacheItem(model.getLineCount(), data.map(item => { + return { + symbol: item.symbol, + provider: this._fakeProvider + }; + })); this._cache.set(model.uri.toString(), item); } @@ -89,7 +86,7 @@ export class CodeLensCache implements ICodeLensCache { const data: Record = Object.create(null); this._cache.forEach((value, key) => { const lines = new Set(); - for (const d of value.data.lenses) { + for (const d of value.data) { lines.add(d.symbol.range.startLineNumber); } data[key] = { @@ -105,14 +102,14 @@ export class CodeLensCache implements ICodeLensCache { const data: Record = JSON.parse(raw); for (const key in data) { const element = data[key]; - const lenses: CodeLens[] = []; + const symbols: ICodeLensData[] = []; for (const line of element.lines) { - lenses.push({ range: new Range(line, 1, line, 11) }); + symbols.push({ + provider: this._fakeProvider, + symbol: { range: new Range(line, 1, line, 11) } + }); } - - const model = new CodeLensModel(); - model.add({ lenses, dispose() { } }, this._fakeProvider); - this._cache.set(key, new CacheItem(element.lineCount, model)); + this._cache.set(key, new CacheItem(element.lineCount, symbols)); } } catch { // ignore... diff --git a/src/vs/editor/contrib/codelens/codelens.ts b/src/vs/editor/contrib/codelens/codelens.ts index bc10d804d7..2d3fd1ec6e 100644 --- a/src/vs/editor/contrib/codelens/codelens.ts +++ b/src/vs/editor/contrib/codelens/codelens.ts @@ -9,59 +9,38 @@ import { illegalArgument, onUnexpectedExternalError } from 'vs/base/common/error import { URI } from 'vs/base/common/uri'; import { registerLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { ITextModel } from 'vs/editor/common/model'; -import { CodeLensProvider, CodeLensProviderRegistry, CodeLens, CodeLensList } from 'vs/editor/common/modes'; +import { CodeLensProvider, CodeLensProviderRegistry, ICodeLensSymbol } from 'vs/editor/common/modes'; import { IModelService } from 'vs/editor/common/services/modelService'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -export interface CodeLensItem { - symbol: CodeLens; +export interface ICodeLensData { + symbol: ICodeLensSymbol; provider: CodeLensProvider; } -export class CodeLensModel { - - lenses: CodeLensItem[] = []; - - private readonly _dispoables = new DisposableStore(); - - dispose(): void { - this._dispoables.dispose(); - } - - add(list: CodeLensList, provider: CodeLensProvider): void { - this._dispoables.add(list); - for (const symbol of list.lenses) { - this.lenses.push({ symbol, provider }); - } - } -} - -export function getCodeLensData(model: ITextModel, token: CancellationToken): Promise { +export function getCodeLensData(model: ITextModel, token: CancellationToken): Promise { + const symbols: ICodeLensData[] = []; const provider = CodeLensProviderRegistry.ordered(model); - const providerRanks = new Map(); - const result = new CodeLensModel(); - const promises = provider.map((provider, i) => { - - providerRanks.set(provider, i); - - return Promise.resolve(provider.provideCodeLenses(model, token)) - .then(list => list && result.add(list, provider)) - .catch(onUnexpectedExternalError); - }); + const promises = provider.map(provider => Promise.resolve(provider.provideCodeLenses(model, token)).then(result => { + if (Array.isArray(result)) { + for (let symbol of result) { + symbols.push({ symbol, provider }); + } + } + }).catch(onUnexpectedExternalError)); return Promise.all(promises).then(() => { - result.lenses = mergeSort(result.lenses, (a, b) => { + return mergeSort(symbols, (a, b) => { // sort by lineNumber, provider-rank, and column if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) { return -1; } else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) { return 1; - } else if (providerRanks.get(a.provider)! < providerRanks.get(b.provider)!) { + } else if (provider.indexOf(a.provider) < provider.indexOf(b.provider)) { return -1; - } else if (providerRanks.get(a.provider)! > providerRanks.get(b.provider)!) { + } else if (provider.indexOf(a.provider) > provider.indexOf(b.provider)) { return 1; } else if (a.symbol.range.startColumn < b.symbol.range.startColumn) { return -1; @@ -71,8 +50,6 @@ export function getCodeLensData(model: ITextModel, token: CancellationToken): Pr return 0; } }); - - return result; }); } @@ -88,12 +65,12 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { throw illegalArgument(); } - const result: CodeLens[] = []; + const result: ICodeLensSymbol[] = []; return getCodeLensData(model, CancellationToken.None).then(value => { let resolve: Promise[] = []; - for (const item of value.lenses) { + for (const item of value) { if (typeof itemResolveCount === 'undefined' || Boolean(item.symbol.command)) { result.push(item.symbol); } else if (itemResolveCount-- > 0 && item.provider.resolveCodeLens) { @@ -101,7 +78,7 @@ registerLanguageCommand('_executeCodeLensProvider', function (accessor, args) { } } - return Promise.all(resolve).finally(() => value.dispose()); + return Promise.all(resolve); }).then(() => { return result; diff --git a/src/vs/editor/contrib/codelens/codelensController.ts b/src/vs/editor/contrib/codelens/codelensController.ts index 2b7960b627..b2b61a2f40 100644 --- a/src/vs/editor/contrib/codelens/codelensController.ts +++ b/src/vs/editor/contrib/codelens/codelensController.ts @@ -5,16 +5,16 @@ import { CancelablePromise, RunOnceScheduler, createCancelablePromise, disposableTimeout } from 'vs/base/common/async'; import { onUnexpectedError, onUnexpectedExternalError } from 'vs/base/common/errors'; -import { dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { StableEditorScrollState } from 'vs/editor/browser/core/editorState'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model'; -import { CodeLensProviderRegistry, CodeLens } from 'vs/editor/common/modes'; -import { CodeLensModel, getCodeLensData, CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; -import { CodeLensWidget, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget'; +import { CodeLensProviderRegistry, ICodeLensSymbol } from 'vs/editor/common/modes'; +import { ICodeLensData, getCodeLensData } from 'vs/editor/contrib/codelens/codelens'; +import { CodeLens, CodeLensHelper } from 'vs/editor/contrib/codelens/codelensWidget'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ICodeLensCache } from 'vs/editor/contrib/codelens/codeLensCache'; @@ -25,13 +25,12 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { private _isEnabled: boolean; - private readonly _globalToDispose = new DisposableStore(); - private readonly _localToDispose = new DisposableStore(); - private _lenses: CodeLensWidget[] = []; - private _currentFindCodeLensSymbolsPromise: CancelablePromise | undefined; - private _currentCodeLensModel: CodeLensModel | undefined; - private _modelChangeCounter: number = 0; - private _currentResolveCodeLensSymbolsPromise: CancelablePromise | undefined; + private _globalToDispose: IDisposable[]; + private _localToDispose: IDisposable[]; + private _lenses: CodeLens[]; + private _currentFindCodeLensSymbolsPromise: CancelablePromise | null; + private _modelChangeCounter: number; + private _currentResolveCodeLensSymbolsPromise: CancelablePromise | null; private _detectVisibleLenses: RunOnceScheduler; constructor( @@ -42,36 +41,41 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { ) { this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; - this._globalToDispose.add(this._editor.onDidChangeModel(() => this._onModelChange())); - this._globalToDispose.add(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); - this._globalToDispose.add(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { + this._globalToDispose = []; + this._localToDispose = []; + this._lenses = []; + this._currentFindCodeLensSymbolsPromise = null; + this._modelChangeCounter = 0; + + this._globalToDispose.push(this._editor.onDidChangeModel(() => this._onModelChange())); + this._globalToDispose.push(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); + this._globalToDispose.push(this._editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { let prevIsEnabled = this._isEnabled; this._isEnabled = this._editor.getConfiguration().contribInfo.codeLens; if (prevIsEnabled !== this._isEnabled) { this._onModelChange(); } })); - this._globalToDispose.add(CodeLensProviderRegistry.onDidChange(this._onModelChange, this)); + this._globalToDispose.push(CodeLensProviderRegistry.onDidChange(this._onModelChange, this)); this._onModelChange(); } dispose(): void { this._localDispose(); - this._globalToDispose.dispose(); + this._globalToDispose = dispose(this._globalToDispose); } private _localDispose(): void { if (this._currentFindCodeLensSymbolsPromise) { this._currentFindCodeLensSymbolsPromise.cancel(); - this._currentFindCodeLensSymbolsPromise = undefined; + this._currentFindCodeLensSymbolsPromise = null; this._modelChangeCounter++; } if (this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise.cancel(); - this._currentResolveCodeLensSymbolsPromise = undefined; + this._currentResolveCodeLensSymbolsPromise = null; } - this._localToDispose.clear(); - dispose(this._currentCodeLensModel); + this._localToDispose = dispose(this._localToDispose); } getId(): string { @@ -100,7 +104,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // no provider -> return but check with // cached lenses. they expire after 30 seconds if (cachedLenses) { - this._localToDispose.add(disposableTimeout(() => { + this._localToDispose.push(disposableTimeout(() => { const cachedLensesNow = this._codeLensCache.get(model); if (cachedLenses === cachedLensesNow) { this._codeLensCache.delete(model); @@ -114,7 +118,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { for (const provider of CodeLensProviderRegistry.all(model)) { if (typeof provider.onDidChange === 'function') { let registration = provider.onDidChange(() => scheduler.schedule()); - this._localToDispose.add(registration); + this._localToDispose.push(registration); } } @@ -132,25 +136,18 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._currentFindCodeLensSymbolsPromise.then(result => { if (counterValue === this._modelChangeCounter) { // only the last one wins - // lifecycle -> dispose old model - dispose(this._currentCodeLensModel); - this._currentCodeLensModel = result; - - // cache model to reduce flicker this._codeLensCache.put(model, result); - - // render lenses this._renderCodeLensSymbols(result); this._detectVisibleLenses.schedule(); } }, onUnexpectedError); }, 250); - this._localToDispose.add(scheduler); - this._localToDispose.add(this._detectVisibleLenses); - this._localToDispose.add(this._editor.onDidChangeModelContent((e) => { + this._localToDispose.push(scheduler); + this._localToDispose.push(this._detectVisibleLenses); + this._localToDispose.push(this._editor.onDidChangeModelContent((e) => { this._editor.changeDecorations((changeAccessor) => { this._editor.changeViewZones((viewAccessor) => { - let toDispose: CodeLensWidget[] = []; + let toDispose: CodeLens[] = []; let lastLensLineNumber: number = -1; this._lenses.forEach((lens) => { @@ -179,15 +176,15 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // Ask for all references again scheduler.schedule(); })); - this._localToDispose.add(this._editor.onDidScrollChange(e => { + this._localToDispose.push(this._editor.onDidScrollChange(e => { if (e.scrollTopChanged && this._lenses.length > 0) { this._detectVisibleLenses.schedule(); } })); - this._localToDispose.add(this._editor.onDidLayoutChange(e => { + this._localToDispose.push(this._editor.onDidLayoutChange(e => { this._detectVisibleLenses.schedule(); })); - this._localToDispose.add(toDisposable(() => { + this._localToDispose.push(toDisposable(() => { if (this._editor.getModel()) { const scrollState = StableEditorScrollState.capture(this._editor); this._editor.changeDecorations((changeAccessor) => { @@ -201,14 +198,14 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._disposeAllLenses(undefined, undefined); } })); - this._localToDispose.add(this._editor.onDidChangeConfiguration(e => { + this._localToDispose.push(this._editor.onDidChangeConfiguration(e => { if (e.fontInfo) { for (const lens of this._lenses) { lens.updateHeight(); } } })); - this._localToDispose.add(this._editor.onMouseUp(e => { + this._localToDispose.push(this._editor.onMouseUp(e => { if (e.target.type === editorBrowser.MouseTargetType.CONTENT_WIDGET && e.target.element && e.target.element.tagName === 'A') { for (const lens of this._lenses) { let command = lens.getCommand(e.target.element as HTMLLinkElement); @@ -231,16 +228,16 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { this._lenses = []; } - private _renderCodeLensSymbols(symbols: CodeLensModel): void { + private _renderCodeLensSymbols(symbols: ICodeLensData[]): void { if (!this._editor.hasModel()) { return; } let maxLineNumber = this._editor.getModel().getLineCount(); - let groups: CodeLensItem[][] = []; - let lastGroup: CodeLensItem[] | undefined; + let groups: ICodeLensData[][] = []; + let lastGroup: ICodeLensData[] | undefined; - for (let symbol of symbols.lenses) { + for (let symbol of symbols) { let line = symbol.symbol.range.startLineNumber; if (line < 1 || line > maxLineNumber) { // invalid code lens @@ -275,7 +272,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { groupsIndex++; codeLensIndex++; } else { - this._lenses.splice(codeLensIndex, 0, new CodeLensWidget(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); + this._lenses.splice(codeLensIndex, 0, new CodeLens(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); codeLensIndex++; groupsIndex++; } @@ -289,7 +286,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { // Create extra symbols while (groupsIndex < groups.length) { - this._lenses.push(new CodeLensWidget(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); + this._lenses.push(new CodeLens(groups[groupsIndex], this._editor, helper, accessor, () => this._detectVisibleLenses.schedule())); groupsIndex++; } @@ -303,7 +300,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { private _onViewportChanged(): void { if (this._currentResolveCodeLensSymbolsPromise) { this._currentResolveCodeLensSymbolsPromise.cancel(); - this._currentResolveCodeLensSymbolsPromise = undefined; + this._currentResolveCodeLensSymbolsPromise = null; } const model = this._editor.getModel(); @@ -311,8 +308,8 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { return; } - const toResolve: CodeLensItem[][] = []; - const lenses: CodeLensWidget[] = []; + const toResolve: ICodeLensData[][] = []; + const lenses: CodeLens[] = []; this._lenses.forEach((lens) => { const request = lens.computeIfNecessary(model); if (request) { @@ -329,7 +326,7 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { const promises = toResolve.map((request, i) => { - const resolvedSymbols = new Array(request.length); + const resolvedSymbols = new Array(request.length); const promises = request.map((request, i) => { if (!request.symbol.command && typeof request.provider.resolveCodeLens === 'function') { return Promise.resolve(request.provider.resolveCodeLens(model, request.symbol, token)).then(symbol => { @@ -349,10 +346,11 @@ export class CodeLensContribution implements editorCommon.IEditorContribution { return Promise.all(promises); }); - this._currentResolveCodeLensSymbolsPromise.catch(err => { + this._currentResolveCodeLensSymbolsPromise.then(() => { + this._currentResolveCodeLensSymbolsPromise = null; + }).catch(err => { + this._currentResolveCodeLensSymbolsPromise = null; onUnexpectedError(err); - }).finally(() => { - this._currentResolveCodeLensSymbolsPromise = undefined; }); } } diff --git a/src/vs/editor/contrib/codelens/codelensWidget.ts b/src/vs/editor/contrib/codelens/codelensWidget.ts index 2f85d841a0..9701a319f4 100644 --- a/src/vs/editor/contrib/codelens/codelensWidget.ts +++ b/src/vs/editor/contrib/codelens/codelensWidget.ts @@ -11,9 +11,9 @@ import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { Range } from 'vs/editor/common/core/range'; import { IModelDecorationsChangeAccessor, IModelDeltaDecoration, ITextModel } from 'vs/editor/common/model'; import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; -import { Command, CodeLens } from 'vs/editor/common/modes'; +import { Command, ICodeLensSymbol } from 'vs/editor/common/modes'; import { editorCodeLensForeground } from 'vs/editor/common/view/editorColorRegistry'; -import { CodeLensItem } from 'vs/editor/contrib/codelens/codelens'; +import { ICodeLensData } from 'vs/editor/contrib/codelens/codelens'; import { editorActiveLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -65,7 +65,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { constructor( editor: editorBrowser.ICodeEditor, symbolRange: Range, - data: CodeLensItem[] + data: ICodeLensData[] ) { this._id = 'codeLensWidget' + (++CodeLensContentWidget._idPool); this._editor = editor; @@ -88,7 +88,7 @@ class CodeLensContentWidget implements editorBrowser.IContentWidget { this._domNode.innerHTML = ' '; } - withCommands(inSymbols: Array, animate: boolean): void { + withCommands(inSymbols: Array, animate: boolean): void { this._commands.clear(); const symbols = coalesce(inSymbols); @@ -189,17 +189,17 @@ export class CodeLensHelper { } } -export class CodeLensWidget { +export class CodeLens { private readonly _editor: editorBrowser.ICodeEditor; private readonly _viewZone: CodeLensViewZone; private readonly _viewZoneId: number; private readonly _contentWidget: CodeLensContentWidget; private _decorationIds: string[]; - private _data: CodeLensItem[]; + private _data: ICodeLensData[]; constructor( - data: CodeLensItem[], + data: ICodeLensData[], editor: editorBrowser.ICodeEditor, helper: CodeLensHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor, @@ -256,7 +256,7 @@ export class CodeLensWidget { }); } - updateCodeLensSymbols(data: CodeLensItem[], helper: CodeLensHelper): void { + updateCodeLensSymbols(data: ICodeLensData[], helper: CodeLensHelper): void { while (this._decorationIds.length) { helper.removeDecoration(this._decorationIds.pop()!); } @@ -270,7 +270,7 @@ export class CodeLensWidget { }); } - computeIfNecessary(model: ITextModel): CodeLensItem[] | null { + computeIfNecessary(model: ITextModel): ICodeLensData[] | null { if (!this._contentWidget.isVisible()) { return null; } @@ -285,7 +285,7 @@ export class CodeLensWidget { return this._data; } - updateCommands(symbols: Array): void { + updateCommands(symbols: Array): void { this._contentWidget.withCommands(symbols, true); for (let i = 0; i < this._data.length; i++) { const resolved = symbols[i]; diff --git a/src/vs/editor/contrib/colorPicker/colorDetector.ts b/src/vs/editor/contrib/colorPicker/colorDetector.ts index bd94aa5b58..40f51d379c 100644 --- a/src/vs/editor/contrib/colorPicker/colorDetector.ts +++ b/src/vs/editor/contrib/colorPicker/colorDetector.ts @@ -7,7 +7,7 @@ import { CancelablePromise, TimeoutTimer, createCancelablePromise } from 'vs/bas import { RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { hash } from 'vs/base/common/hash'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -22,13 +22,14 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur const MAX_DECORATORS = 500; -export class ColorDetector extends Disposable implements IEditorContribution { +export class ColorDetector implements IEditorContribution { private static readonly ID: string = 'editor.contrib.colorDetector'; static RECOMPUTE_TIME = 1000; // ms - private readonly _localToDispose = this._register(new DisposableStore()); + private _globalToDispose: IDisposable[] = []; + private _localToDispose: IDisposable[] = []; private _computePromise: CancelablePromise | null; private _timeoutTimer: TimeoutTimer | null; @@ -44,14 +45,13 @@ export class ColorDetector extends Disposable implements IEditorContribution { @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, @IConfigurationService private readonly _configurationService: IConfigurationService ) { - super(); - this._register(_editor.onDidChangeModel((e) => { + this._globalToDispose.push(_editor.onDidChangeModel((e) => { this._isEnabled = this.isEnabled(); this.onModelChanged(); })); - this._register(_editor.onDidChangeModelLanguage((e) => this.onModelChanged())); - this._register(ColorProviderRegistry.onDidChange((e) => this.onModelChanged())); - this._register(_editor.onDidChangeConfiguration((e) => { + this._globalToDispose.push(_editor.onDidChangeModelLanguage((e) => this.onModelChanged())); + this._globalToDispose.push(ColorProviderRegistry.onDidChange((e) => this.onModelChanged())); + this._globalToDispose.push(_editor.onDidChangeConfiguration((e) => { let prevIsEnabled = this._isEnabled; this._isEnabled = this.isEnabled(); if (prevIsEnabled !== this._isEnabled) { @@ -98,7 +98,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { dispose(): void { this.stop(); this.removeAllDecorations(); - super.dispose(); + this._globalToDispose = dispose(this._globalToDispose); } private onModelChanged(): void { @@ -113,7 +113,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { return; } - this._localToDispose.add(this._editor.onDidChangeModelContent((e) => { + this._localToDispose.push(this._editor.onDidChangeModelContent((e) => { if (!this._timeoutTimer) { this._timeoutTimer = new TimeoutTimer(); this._timeoutTimer.cancelAndSet(() => { @@ -149,7 +149,7 @@ export class ColorDetector extends Disposable implements IEditorContribution { this._computePromise.cancel(); this._computePromise = null; } - this._localToDispose.clear(); + this._localToDispose = dispose(this._localToDispose); } private updateDecorations(colorDatas: IColorData[]): void { diff --git a/src/vs/editor/contrib/contextmenu/contextmenu.ts b/src/vs/editor/contrib/contextmenu/contextmenu.ts index 34ec21d862..a77302fc2e 100644 --- a/src/vs/editor/contrib/contextmenu/contextmenu.ts +++ b/src/vs/editor/contrib/contextmenu/contextmenu.ts @@ -125,7 +125,7 @@ export class ContextMenuController implements IEditorContribution { } } - private _getMenuActions(model: ITextModel): ReadonlyArray { + private _getMenuActions(model: ITextModel): IAction[] { const result: IAction[] = []; let contextMenu = this._menuService.createMenu(MenuId.EditorContext, this._contextKeyService); @@ -141,7 +141,7 @@ export class ContextMenuController implements IEditorContribution { return result; } - private _doShowContextMenu(actions: ReadonlyArray, anchor: IAnchor | null = null): void { + private _doShowContextMenu(actions: IAction[], anchor: IAnchor | null = null): void { if (!this._editor.hasModel()) { return; } diff --git a/src/vs/editor/contrib/dnd/dnd.ts b/src/vs/editor/contrib/dnd/dnd.ts index bb50bac3b8..e2957bab58 100644 --- a/src/vs/editor/contrib/dnd/dnd.ts +++ b/src/vs/editor/contrib/dnd/dnd.ts @@ -5,7 +5,7 @@ import 'vs/css!./dnd'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isMacintosh } from 'vs/base/common/platform'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ICodeEditor, IEditorMouseEvent, IMouseTarget, MouseTargetType } from 'vs/editor/browser/editorBrowser'; @@ -28,11 +28,12 @@ function hasTriggerModifier(e: IKeyboardEvent | IMouseEvent): boolean { } } -export class DragAndDropController extends Disposable implements editorCommon.IEditorContribution { +export class DragAndDropController implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.dragAndDrop'; private readonly _editor: ICodeEditor; + private _toUnhook: IDisposable[]; private _dragSelection: Selection | null; private _dndDecorationIds: string[]; private _mouseDown: boolean; @@ -44,15 +45,15 @@ export class DragAndDropController extends Disposable implements editorCommon.IE } constructor(editor: ICodeEditor) { - super(); this._editor = editor; - this._register(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); - this._register(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); - this._register(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); - this._register(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); - this._register(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e))); - this._register(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); - this._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur())); + this._toUnhook = []; + this._toUnhook.push(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); + this._toUnhook.push(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); + this._toUnhook.push(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); + this._toUnhook.push(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); + this._toUnhook.push(this._editor.onKeyDown((e: IKeyboardEvent) => this.onEditorKeyDown(e))); + this._toUnhook.push(this._editor.onKeyUp((e: IKeyboardEvent) => this.onEditorKeyUp(e))); + this._toUnhook.push(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur())); this._dndDecorationIds = []; this._mouseDown = false; this._modifierPressed = false; @@ -227,7 +228,7 @@ export class DragAndDropController extends Disposable implements editorCommon.IE this._dragSelection = null; this._mouseDown = false; this._modifierPressed = false; - super.dispose(); + this._toUnhook = dispose(this._toUnhook); } } diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 76be0e50ad..61cbcdc127 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -99,29 +99,29 @@ export abstract class SimpleFindWidget extends Widget { } })); - const prevBtn = this._register(new SimpleButton({ + const prevBtn = new SimpleButton({ label: NLS_PREVIOUS_MATCH_BTN_LABEL, className: 'previous', onTrigger: () => { this.find(true); } - })); + }); - const nextBtn = this._register(new SimpleButton({ + const nextBtn = new SimpleButton({ label: NLS_NEXT_MATCH_BTN_LABEL, className: 'next', onTrigger: () => { this.find(false); } - })); + }); - const closeBtn = this._register(new SimpleButton({ + const closeBtn = new SimpleButton({ label: NLS_CLOSE_BTN_LABEL, className: 'close-fw', onTrigger: () => { this.hide(); } - })); + }); this._innerDomNode = document.createElement('div'); this._innerDomNode.classList.add('simple-find-part'); diff --git a/src/vs/editor/contrib/folding/folding.ts b/src/vs/editor/contrib/folding/folding.ts index ef20ff7552..9ec22649c4 100644 --- a/src/vs/editor/contrib/folding/folding.ts +++ b/src/vs/editor/contrib/folding/folding.ts @@ -9,7 +9,7 @@ import * as types from 'vs/base/common/types'; import { escapeRegExpCharacters } from 'vs/base/common/strings'; import { RunOnceScheduler, Delayer, CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; import { KeyCode, KeyMod, KeyChord } from 'vs/base/common/keyCodes'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ScrollType, IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, registerInstantiatedEditorAction } from 'vs/editor/browser/editorExtensions'; @@ -46,7 +46,7 @@ interface FoldingStateMemento { provider?: string; } -export class FoldingController extends Disposable implements IEditorContribution { +export class FoldingController implements IEditorContribution { static MAX_FOLDING_REGIONS = 5000; @@ -73,25 +73,27 @@ export class FoldingController extends Disposable implements IEditorContribution private foldingModelPromise: Promise | null; private updateScheduler: Delayer | null; + private globalToDispose: IDisposable[]; private cursorChangedScheduler: RunOnceScheduler | null; - private readonly localToDispose = this._register(new DisposableStore()); + private localToDispose: IDisposable[]; constructor(editor: ICodeEditor) { - super(); this.editor = editor; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; this._autoHideFoldingControls = this.editor.getConfiguration().contribInfo.showFoldingControls === 'mouseover'; this._useFoldingProviders = this.editor.getConfiguration().contribInfo.foldingStrategy !== 'indentation'; + this.globalToDispose = []; + this.localToDispose = []; this.foldingDecorationProvider = new FoldingDecorationProvider(editor); this.foldingDecorationProvider.autoHideFoldingControls = this._autoHideFoldingControls; - this._register(this.editor.onDidChangeModel(() => this.onModelChanged())); + this.globalToDispose.push(this.editor.onDidChangeModel(() => this.onModelChanged())); - this._register(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { + this.globalToDispose.push(this.editor.onDidChangeConfiguration((e: IConfigurationChangedEvent) => { if (e.contribInfo) { let oldIsEnabled = this._isEnabled; this._isEnabled = this.editor.getConfiguration().contribInfo.folding; @@ -111,6 +113,7 @@ export class FoldingController extends Disposable implements IEditorContribution } } })); + this.globalToDispose.push({ dispose: () => dispose(this.localToDispose) }); this.onModelChanged(); } @@ -118,6 +121,10 @@ export class FoldingController extends Disposable implements IEditorContribution return ID; } + public dispose(): void { + this.globalToDispose = dispose(this.globalToDispose); + } + /** * Store view state. */ @@ -166,7 +173,7 @@ export class FoldingController extends Disposable implements IEditorContribution } private onModelChanged(): void { - this.localToDispose.clear(); + this.localToDispose = dispose(this.localToDispose); let model = this.editor.getModel(); if (!this._isEnabled || !model || model.isTooLargeForTokenization()) { @@ -175,23 +182,23 @@ export class FoldingController extends Disposable implements IEditorContribution } this.foldingModel = new FoldingModel(model, this.foldingDecorationProvider); - this.localToDispose.add(this.foldingModel); + this.localToDispose.push(this.foldingModel); this.hiddenRangeModel = new HiddenRangeModel(this.foldingModel); - this.localToDispose.add(this.hiddenRangeModel); - this.localToDispose.add(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr))); + this.localToDispose.push(this.hiddenRangeModel); + this.localToDispose.push(this.hiddenRangeModel.onDidChange(hr => this.onHiddenRangesChanges(hr))); this.updateScheduler = new Delayer(200); this.cursorChangedScheduler = new RunOnceScheduler(() => this.revealCursor(), 200); - this.localToDispose.add(this.cursorChangedScheduler); - this.localToDispose.add(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); - this.localToDispose.add(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well - this.localToDispose.add(this.editor.onDidChangeModelContent(() => this.onModelContentChanged())); - this.localToDispose.add(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged())); - this.localToDispose.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); - this.localToDispose.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); - this.localToDispose.add({ + this.localToDispose.push(this.cursorChangedScheduler); + this.localToDispose.push(FoldingRangeProviderRegistry.onDidChange(() => this.onFoldingStrategyChanged())); + this.localToDispose.push(this.editor.onDidChangeModelLanguageConfiguration(() => this.onFoldingStrategyChanged())); // covers model language changes as well + this.localToDispose.push(this.editor.onDidChangeModelContent(() => this.onModelContentChanged())); + this.localToDispose.push(this.editor.onDidChangeCursorPosition(() => this.onCursorPositionChanged())); + this.localToDispose.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); + this.localToDispose.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); + this.localToDispose.push({ dispose: () => { if (this.foldingRegionPromise) { this.foldingRegionPromise.cancel(); diff --git a/src/vs/editor/contrib/format/formatActions.ts b/src/vs/editor/contrib/format/formatActions.ts index ecf2503387..b363cba00f 100644 --- a/src/vs/editor/contrib/format/formatActions.ts +++ b/src/vs/editor/contrib/format/formatActions.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { CancellationToken } from 'vs/base/common/cancellation'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, registerEditorAction, registerEditorContribution, ServicesAccessor } from 'vs/editor/browser/editorExtensions'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; @@ -30,18 +30,18 @@ class FormatOnType implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.autoFormat'; private readonly _editor: ICodeEditor; - private readonly _callOnDispose = new DisposableStore(); - private readonly _callOnModel = new DisposableStore(); + private _callOnDispose: IDisposable[] = []; + private _callOnModel: IDisposable[] = []; constructor( editor: ICodeEditor, @IEditorWorkerService private readonly _workerService: IEditorWorkerService ) { this._editor = editor; - this._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update())); - this._callOnDispose.add(editor.onDidChangeModel(() => this._update())); - this._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update())); - this._callOnDispose.add(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this)); + this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update())); + this._callOnDispose.push(editor.onDidChangeModel(() => this._update())); + this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update())); + this._callOnDispose.push(OnTypeFormattingEditProviderRegistry.onDidChange(this._update, this)); } getId(): string { @@ -49,14 +49,14 @@ class FormatOnType implements editorCommon.IEditorContribution { } dispose(): void { - this._callOnDispose.dispose(); - this._callOnModel.dispose(); + this._callOnDispose = dispose(this._callOnDispose); + this._callOnModel = dispose(this._callOnModel); } private _update(): void { // clean up - this._callOnModel.clear(); + this._callOnModel = dispose(this._callOnModel); // we are disabled if (!this._editor.getConfiguration().contribInfo.formatOnType) { @@ -81,7 +81,7 @@ class FormatOnType implements editorCommon.IEditorContribution { for (let ch of support.autoFormatTriggerCharacters) { triggerChars.add(ch.charCodeAt(0)); } - this._callOnModel.add(this._editor.onDidType((text: string) => { + this._callOnModel.push(this._editor.onDidType((text: string) => { let lastCharCode = text.charCodeAt(text.length - 1); if (triggerChars.has(lastCharCode)) { this._trigger(String.fromCharCode(lastCharCode)); @@ -156,17 +156,20 @@ class FormatOnPaste implements editorCommon.IEditorContribution { private static readonly ID = 'editor.contrib.formatOnPaste'; - private readonly _callOnDispose = new DisposableStore(); - private readonly _callOnModel = new DisposableStore(); + private _callOnDispose: IDisposable[]; + private _callOnModel: IDisposable[]; constructor( private readonly editor: ICodeEditor, @IInstantiationService private readonly _instantiationService: IInstantiationService, ) { - this._callOnDispose.add(editor.onDidChangeConfiguration(() => this._update())); - this._callOnDispose.add(editor.onDidChangeModel(() => this._update())); - this._callOnDispose.add(editor.onDidChangeModelLanguage(() => this._update())); - this._callOnDispose.add(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this)); + this._callOnDispose = []; + this._callOnModel = []; + + this._callOnDispose.push(editor.onDidChangeConfiguration(() => this._update())); + this._callOnDispose.push(editor.onDidChangeModel(() => this._update())); + this._callOnDispose.push(editor.onDidChangeModelLanguage(() => this._update())); + this._callOnDispose.push(DocumentRangeFormattingEditProviderRegistry.onDidChange(this._update, this)); } getId(): string { @@ -174,14 +177,14 @@ class FormatOnPaste implements editorCommon.IEditorContribution { } dispose(): void { - this._callOnDispose.dispose(); - this._callOnModel.dispose(); + this._callOnDispose = dispose(this._callOnDispose); + this._callOnModel = dispose(this._callOnModel); } private _update(): void { // clean up - this._callOnModel.dispose(); + this._callOnModel = dispose(this._callOnModel); // we are disabled if (!this.editor.getConfiguration().contribInfo.formatOnPaste) { @@ -198,7 +201,7 @@ class FormatOnPaste implements editorCommon.IEditorContribution { return; } - this._callOnModel.add(this.editor.onDidPaste(range => this._trigger(range))); + this._callOnModel.push(this.editor.onDidPaste(range => this._trigger(range))); } private _trigger(range: Range): void { diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts index 4497e20fa7..68f2358f4f 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionCommands.ts @@ -25,7 +25,7 @@ import { MenuId, MenuRegistry } from 'vs/platform/actions/common/actions'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { getDefinitionsAtPosition, getImplementationsAtPosition, getTypeDefinitionsAtPosition, getDeclarationsAtPosition } from './goToDefinition'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { EditorStateCancellationTokenSource, CodeEditorStateFlag } from 'vs/editor/browser/core/editorState'; @@ -58,7 +58,7 @@ export class DefinitionAction extends EditorAction { } const notificationService = accessor.get(INotificationService); const editorService = accessor.get(ICodeEditorService); - const progressService = accessor.get(ILocalProgressService); + const progressService = accessor.get(IProgressService); const symbolNavService = accessor.get(ISymbolNavigationService); const model = editor.getModel(); @@ -176,6 +176,7 @@ export class DefinitionAction extends EditorAction { resource: reference.uri, options: { selection: Range.collapseToStart(range), + revealIfOpened: true, revealInCenterIfOutsideViewport: true } }, editor, sideBySide); diff --git a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts index ef5057bd51..b3d90178f0 100644 --- a/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts +++ b/src/vs/editor/contrib/goToDefinition/goToDefinitionResultsNavigation.ts @@ -13,11 +13,11 @@ import { registerEditorCommand, EditorCommand } from 'vs/editor/browser/editorEx import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { Range } from 'vs/editor/common/core/range'; -import { dispose, IDisposable, combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, dispose, combinedDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { Emitter, Event } from 'vs/base/common/event'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { localize } from 'vs/nls'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { INotificationService } from 'vs/platform/notification/common/notification'; export const ctxHasSymbols = new RawContextKey('hasSymbols', false); @@ -38,14 +38,14 @@ class SymbolNavigationService implements ISymbolNavigationService { private _currentModel?: ReferencesModel = undefined; private _currentIdx: number = -1; - private _currentState?: IDisposable; - private _currentMessage?: IDisposable; + private _currentDisposables: IDisposable[] = []; + private _currentMessage?: IDisposable = undefined; private _ignoreEditorChange: boolean = false; constructor( @IContextKeyService contextKeyService: IContextKeyService, @ICodeEditorService private readonly _editorService: ICodeEditorService, - @INotificationService private readonly _notificationService: INotificationService, + @IStatusbarService private readonly _statusbarService: IStatusbarService, @IKeybindingService private readonly _keybindingService: IKeybindingService, ) { this._ctxHasSymbols = ctxHasSymbols.bindTo(contextKeyService); @@ -53,7 +53,7 @@ class SymbolNavigationService implements ISymbolNavigationService { reset(): void { this._ctxHasSymbols.reset(); - dispose(this._currentState); + dispose(this._currentDisposables); dispose(this._currentMessage); this._currentModel = undefined; this._currentIdx = -1; @@ -72,8 +72,8 @@ class SymbolNavigationService implements ISymbolNavigationService { this._ctxHasSymbols.set(true); this._showMessage(); - const editorState = new EditorState(this._editorService); - const listener = editorState.onDidChange(_ => { + const editorStatus = new EditorStatus(this._editorService); + const listener = editorStatus.onDidChange(_ => { if (this._ignoreEditorChange) { return; @@ -104,7 +104,7 @@ class SymbolNavigationService implements ISymbolNavigationService { } }); - this._currentState = combinedDisposable(editorState, listener); + this._currentDisposables = [editorStatus, listener]; } revealNext(source: ICodeEditor): Promise { @@ -126,7 +126,8 @@ class SymbolNavigationService implements ISymbolNavigationService { resource: reference.uri, options: { selection: Range.collapseToStart(reference.range), - revealInCenterIfOutsideViewport: true + revealInCenterIfOutsideViewport: true, + revealIfOpened: true } }, source).finally(() => { this._ignoreEditorChange = false; @@ -140,10 +141,10 @@ class SymbolNavigationService implements ISymbolNavigationService { const kb = this._keybindingService.lookupKeybinding('editor.gotoNextSymbolFromResult'); const message = kb - ? localize('location.kb', "Symbol {0} of {1}, {2} for next", this._currentIdx + 1, this._currentModel!.references.length, kb.getLabel()) + ? localize('location.kb', "Symbol {0} of {1}, press {2} to reveal next", this._currentIdx + 1, this._currentModel!.references.length, kb.getLabel()) : localize('location', "Symbol {0} of {1}", this._currentIdx + 1, this._currentModel!.references.length); - this._currentMessage = this._notificationService.status(message); + this._currentMessage = this._statusbarService.setStatusMessage(message); } } @@ -182,31 +183,26 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ // -class EditorState { +class EditorStatus extends Disposable { private readonly _listener = new Map(); - private readonly _disposables = new DisposableStore(); private readonly _onDidChange = new Emitter<{ editor: ICodeEditor }>(); readonly onDidChange: Event<{ editor: ICodeEditor }> = this._onDidChange.event; constructor(@ICodeEditorService editorService: ICodeEditorService) { - this._disposables.add(editorService.onCodeEditorRemove(this._onDidRemoveEditor, this)); - this._disposables.add(editorService.onCodeEditorAdd(this._onDidAddEditor, this)); + super(); + this._register(this._onDidChange); + this._register(editorService.onCodeEditorRemove(this._onDidRemoveEditor, this)); + this._register(editorService.onCodeEditorAdd(this._onDidAddEditor, this)); editorService.listCodeEditors().forEach(this._onDidAddEditor, this); } - dispose(): void { - this._disposables.dispose(); - this._onDidChange.dispose(); - this._listener.forEach(dispose); - } - private _onDidAddEditor(editor: ICodeEditor): void { - this._listener.set(editor, combinedDisposable( + this._listener.set(editor, combinedDisposable([ editor.onDidChangeCursorPosition(_ => this._onDidChange.fire({ editor })), editor.onDidChangeModelContent(_ => this._onDidChange.fire({ editor })), - )); + ])); } private _onDidRemoveEditor(editor: ICodeEditor): void { diff --git a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts index d67b01c0b7..9ed7491b50 100644 --- a/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts +++ b/src/vs/editor/contrib/gotoError/gotoErrorWidget.ts @@ -6,14 +6,15 @@ import 'vs/css!./media/gotoErrorWidget'; import * as nls from 'vs/nls'; import * as dom from 'vs/base/browser/dom'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IMarker, MarkerSeverity, IRelatedInformation } from 'vs/platform/markers/common/markers'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; -import { registerColor, oneOf, textLinkForeground, editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/platform/theme/common/colorRegistry'; +import { registerColor, oneOf, textLinkForeground } from 'vs/platform/theme/common/colorRegistry'; import { IThemeService, ITheme, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { Color } from 'vs/base/common/color'; +import { editorErrorForeground, editorErrorBorder, editorWarningForeground, editorWarningBorder, editorInfoForeground, editorInfoBorder } from 'vs/editor/common/view/editorColorRegistry'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { ScrollType } from 'vs/editor/common/editorCommon'; @@ -26,7 +27,6 @@ import { IAction } from 'vs/base/common/actions'; import { IActionBarOptions, ActionsOrientation } from 'vs/base/browser/ui/actionbar/actionbar'; import { peekViewTitleForeground, peekViewTitleInfoForeground } from 'vs/editor/contrib/referenceSearch/referencesWidget'; import { AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; class MessageWidget { @@ -168,9 +168,8 @@ export class MarkerNavigationWidget extends PeekViewWidget { private _parentContainer: HTMLElement; private _container: HTMLElement; - private _icon: HTMLElement; private _message: MessageWidget; - private readonly _callOnDispose = new DisposableStore(); + private _callOnDispose: IDisposable[] = []; private _severity: MarkerSeverity; private _backgroundColor?: Color; private _onDidSelectRelatedInformation = new Emitter(); @@ -180,7 +179,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { constructor( editor: ICodeEditor, - private readonly actions: ReadonlyArray, + private readonly actions: IAction[], private readonly _themeService: IThemeService ) { super(editor, { showArrow: true, showFrame: true, isAccessible: true }); @@ -188,7 +187,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { this._backgroundColor = Color.white; this._applyTheme(_themeService.getTheme()); - this._callOnDispose.add(_themeService.onThemeChange(this._applyTheme.bind(this))); + this._callOnDispose.push(_themeService.onThemeChange(this._applyTheme.bind(this))); this.create(); } @@ -219,7 +218,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { } dispose(): void { - this._callOnDispose.dispose(); + this._callOnDispose = dispose(this._callOnDispose); super.dispose(); } @@ -232,10 +231,6 @@ export class MarkerNavigationWidget extends PeekViewWidget { this._actionbarWidget.push(this.actions, { label: false, icon: true }); } - protected _fillTitleIcon(container: HTMLElement): void { - this._icon = dom.append(container, dom.$('')); - } - protected _getActionBarOptions(): IActionBarOptions { return { orientation: ActionsOrientation.HORIZONTAL_REVERSE @@ -252,7 +247,7 @@ export class MarkerNavigationWidget extends PeekViewWidget { container.appendChild(this._container); this._message = new MessageWidget(this._container, this.editor, related => this._onDidSelectRelatedInformation.fire(related)); - this._disposables.add(this._message); + this._disposables.push(this._message); } show(where: Position, heightInLines: number): void { @@ -283,7 +278,13 @@ export class MarkerNavigationWidget extends PeekViewWidget { : nls.localize('change', "{0} of {1} problem", markerIdx, markerCount); this.setTitle(basename(model.uri), detail); } - this._icon.className = SeverityIcon.className(MarkerSeverity.toSeverity(this._severity)); + let headingIconClassName = 'error'; + if (this._severity === MarkerSeverity.Warning) { + headingIconClassName = 'warning'; + } else if (this._severity === MarkerSeverity.Info) { + headingIconClassName = 'info'; + } + this.setTitleIcon(headingIconClassName); this.editor.revealPositionInCenter(position, ScrollType.Smooth); diff --git a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css index 1a0be0be1a..d24b98149f 100644 --- a/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css +++ b/src/vs/editor/contrib/gotoError/media/gotoErrorWidget.css @@ -5,10 +5,28 @@ /* marker zone */ -.monaco-editor .peekview-widget .head .peekview-title .severity-icon { - display: inline-block; - vertical-align: text-top; - margin-right: 4px; +.monaco-editor .peekview-widget .head .peekview-title .icon.warning { + background: url('status-warning.svg') center center no-repeat; +} + +.monaco-editor .peekview-widget .head .peekview-title .icon.error { + background: url('status-error.svg') center center no-repeat; +} + +.monaco-editor .peekview-widget .head .peekview-title .icon.info { + background: url('status-info.svg') center center no-repeat; +} + +.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.warning { + background: url('status-warning-inverse.svg') center center no-repeat; +} + +.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.error { + background: url('status-error-inverse.svg') center center no-repeat; +} + +.vs-dark .monaco-editor .peekview-widget .head .peekview-title .icon.info { + background: url('status-info-inverse.svg') center center no-repeat; } .monaco-editor .marker-widget { diff --git a/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg new file mode 100644 index 0000000000..3c852a7ffd --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-error-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-error.svg b/src/vs/editor/contrib/gotoError/media/status-error.svg new file mode 100644 index 0000000000..a1ddb39fed --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg new file mode 100644 index 0000000000..d38c363e0e --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-info-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-info.svg b/src/vs/editor/contrib/gotoError/media/status-info.svg new file mode 100644 index 0000000000..6e2e22f67b --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg b/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg new file mode 100644 index 0000000000..df44e61b32 --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-warning-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/gotoError/media/status-warning.svg b/src/vs/editor/contrib/gotoError/media/status-warning.svg new file mode 100644 index 0000000000..f4e2a84b0a --- /dev/null +++ b/src/vs/editor/contrib/gotoError/media/status-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/editor/contrib/hover/hover.ts b/src/vs/editor/contrib/hover/hover.ts index abdfcce355..bca65f0fa7 100644 --- a/src/vs/editor/contrib/hover/hover.ts +++ b/src/vs/editor/contrib/hover/hover.ts @@ -7,7 +7,7 @@ import 'vs/css!./hover'; import * as nls from 'vs/nls'; import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { IEmptyContentData } from 'vs/editor/browser/controller/mouseTarget'; import { ICodeEditor, IEditorMouseEvent, MouseTargetType } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; @@ -34,7 +34,7 @@ export class ModesHoverController implements IEditorContribution { private static readonly ID = 'editor.contrib.hover'; - private readonly _toUnhook = new DisposableStore(); + private _toUnhook: IDisposable[]; private readonly _didChangeConfigurationHandler: IDisposable; private _contentWidget: ModesContentHoverWidget; @@ -73,6 +73,8 @@ export class ModesHoverController implements IEditorContribution { @ICommandService private readonly _commandService: ICommandService, @IThemeService private readonly _themeService: IThemeService ) { + this._toUnhook = []; + this._isMouseDown = false; this._hoverClicked = false; @@ -94,22 +96,22 @@ export class ModesHoverController implements IEditorContribution { this._isHoverEnabled = hoverOpts.enabled; this._isHoverSticky = hoverOpts.sticky; if (this._isHoverEnabled) { - this._toUnhook.add(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); - this._toUnhook.add(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); - this._toUnhook.add(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); - this._toUnhook.add(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); - this._toUnhook.add(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged())); + this._toUnhook.push(this._editor.onMouseDown((e: IEditorMouseEvent) => this._onEditorMouseDown(e))); + this._toUnhook.push(this._editor.onMouseUp((e: IEditorMouseEvent) => this._onEditorMouseUp(e))); + this._toUnhook.push(this._editor.onMouseMove((e: IEditorMouseEvent) => this._onEditorMouseMove(e))); + this._toUnhook.push(this._editor.onKeyDown((e: IKeyboardEvent) => this._onKeyDown(e))); + this._toUnhook.push(this._editor.onDidChangeModelDecorations(() => this._onModelDecorationsChanged())); } else { - this._toUnhook.add(this._editor.onMouseMove(hideWidgetsEventHandler)); + this._toUnhook.push(this._editor.onMouseMove(hideWidgetsEventHandler)); } - this._toUnhook.add(this._editor.onMouseLeave(hideWidgetsEventHandler)); - this._toUnhook.add(this._editor.onDidChangeModel(hideWidgetsEventHandler)); - this._toUnhook.add(this._editor.onDidScrollChange((e: IScrollEvent) => this._onEditorScrollChanged(e))); + this._toUnhook.push(this._editor.onMouseLeave(hideWidgetsEventHandler)); + this._toUnhook.push(this._editor.onDidChangeModel(hideWidgetsEventHandler)); + this._toUnhook.push(this._editor.onDidScrollChange((e: IScrollEvent) => this._onEditorScrollChanged(e))); } private _unhookEvents(): void { - this._toUnhook.clear(); + this._toUnhook = dispose(this._toUnhook); } private _onModelDecorationsChanged(): void { @@ -225,7 +227,6 @@ export class ModesHoverController implements IEditorContribution { public dispose(): void { this._unhookEvents(); - this._toUnhook.dispose(); this._didChangeConfigurationHandler.dispose(); if (this._glyphWidget) { diff --git a/src/vs/editor/contrib/hover/hoverWidgets.ts b/src/vs/editor/contrib/hover/hoverWidgets.ts index 7ff6243bce..ece230a25c 100644 --- a/src/vs/editor/contrib/hover/hoverWidgets.ts +++ b/src/vs/editor/contrib/hover/hoverWidgets.ts @@ -8,6 +8,7 @@ import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Widget } from 'vs/base/browser/ui/widget'; import { KeyCode } from 'vs/base/common/keyCodes'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as editorBrowser from 'vs/editor/browser/editorBrowser'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; import { Position } from 'vs/editor/common/core/position'; @@ -24,6 +25,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent protected _showAtRange: Range | null; private _stoleFocus: boolean; private readonly scrollbar: DomScrollableElement; + private disposables: IDisposable[] = []; // Editor.IContentWidget.allowEditorOverflow public allowEditorOverflow = true; @@ -51,7 +53,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent this._domNode.className = 'monaco-editor-hover-content'; this.scrollbar = new DomScrollableElement(this._domNode, {}); - this._register(this.scrollbar); + this.disposables.push(this.scrollbar); this._containerDomNode.appendChild(this.scrollbar.getDomNode()); this.onkeydown(this._containerDomNode, (e: IKeyboardEvent) => { @@ -127,6 +129,7 @@ export class ContentHoverWidget extends Widget implements editorBrowser.IContent public dispose(): void { this._editor.removeContentWidget(this); + this.disposables = dispose(this.disposables); super.dispose(); } diff --git a/src/vs/editor/contrib/hover/modesContentHover.ts b/src/vs/editor/contrib/hover/modesContentHover.ts index 8add6d787d..966de575cc 100644 --- a/src/vs/editor/contrib/hover/modesContentHover.ts +++ b/src/vs/editor/contrib/hover/modesContentHover.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Color, RGBA } from 'vs/base/common/color'; import { IMarkdownString, MarkdownString, isEmptyMarkdownString, markedStringsEquals } from 'vs/base/common/htmlContent'; -import { Disposable, IDisposable, toDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -187,10 +187,6 @@ class ModesContentComputer implements IHoverComputer { } } -interface ActionSet extends IDisposable { - readonly actions: Action[]; -} - export class ModesContentHoverWidget extends ContentHoverWidget { static readonly ID = 'editor.contrib.modesContentHoverWidget'; @@ -440,7 +436,7 @@ export class ModesContentHoverWidget extends ContentHoverWidget { this.updateContents(fragment); this._colorPicker.layout(); - this.renderDisposable = combinedDisposable(colorListener, colorChangeListener, widget, ...markdownDisposeables); + this.renderDisposable = combinedDisposable([colorListener, colorChangeListener, widget, ...markdownDisposeables]); }); } else { if (msg instanceof MarkerHover) { @@ -530,25 +526,24 @@ export class ModesContentHoverWidget extends ContentHoverWidget { private renderMarkerStatusbar(markerHover: MarkerHover): HTMLElement { const hoverElement = $('div.hover-row.status-bar'); - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const actionsElement = dom.append(hoverElement, $('div.actions')); - disposables.add(this.renderAction(actionsElement, { + disposables.push(this.renderAction(actionsElement, { label: nls.localize('quick fixes', "Quick Fix..."), commandId: QuickFixAction.Id, run: async (target) => { const codeActionsPromise = this.getCodeActions(markerHover.marker); - disposables.add(toDisposable(() => codeActionsPromise.cancel())); + disposables.push(toDisposable(() => codeActionsPromise.cancel())); const actions = await codeActionsPromise; - disposables.add(actions); const elementPosition = dom.getDomNodePagePosition(target); this._contextMenuService.showContextMenu({ getAnchor: () => ({ x: elementPosition.left + 6, y: elementPosition.top + elementPosition.height + 6 }), - getActions: () => actions.actions + getActions: () => actions }); } })); if (markerHover.marker.severity === MarkerSeverity.Error || markerHover.marker.severity === MarkerSeverity.Warning || markerHover.marker.severity === MarkerSeverity.Info) { - disposables.add(this.renderAction(actionsElement, { + disposables.push(this.renderAction(actionsElement, { label: nls.localize('peek problem', "Peek Problem"), commandId: NextMarkerAction.ID, run: () => { @@ -558,37 +553,24 @@ export class ModesContentHoverWidget extends ContentHoverWidget { } })); } - this.renderDisposable = disposables; + this.renderDisposable = combinedDisposable(disposables); return hoverElement; } - private getCodeActions(marker: IMarker): CancelablePromise { + private getCodeActions(marker: IMarker): CancelablePromise { return createCancelablePromise(async cancellationToken => { const codeActions = await getCodeActions(this._editor.getModel()!, new Range(marker.startLineNumber, marker.startColumn, marker.endLineNumber, marker.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); if (codeActions.actions.length) { - const disposables = new DisposableStore(); - const actions: Action[] = []; - for (const codeAction of codeActions.actions) { - disposables.add(disposables); - actions.push(new Action( - codeAction.command ? codeAction.command.id : codeAction.title, - codeAction.title, - undefined, - true, - () => applyCodeAction(codeAction, this._bulkEditService, this._commandService))); - } - return { - actions: actions, - dispose: () => disposables.dispose() - }; + return codeActions.actions.map(codeAction => new Action( + codeAction.command ? codeAction.command.id : codeAction.title, + codeAction.title, + undefined, + true, + () => applyCodeAction(codeAction, this._bulkEditService, this._commandService))); } - - return { - actions: [ - new Action('', nls.localize('editor.action.quickFix.noneMessage', "No code actions available")) - ], - dispose() { } - }; + return [ + new Action('', nls.localize('editor.action.quickFix.noneMessage', "No code actions available")) + ]; }); } diff --git a/src/vs/editor/contrib/links/getLinks.ts b/src/vs/editor/contrib/links/getLinks.ts index 883b00ba04..b8d0ea3b42 100644 --- a/src/vs/editor/contrib/links/getLinks.ts +++ b/src/vs/editor/contrib/links/getLinks.ts @@ -27,8 +27,7 @@ export class Link implements ILink { toJSON(): ILink { return { range: this.range, - url: this.url, - tooltip: this.tooltip + url: this.url }; } @@ -40,10 +39,6 @@ export class Link implements ILink { return this._link.url; } - get tooltip(): string | undefined { - return this._link.tooltip; - } - resolve(token: CancellationToken): Promise { if (this._link.url) { try { @@ -148,14 +143,7 @@ export function getLinks(model: ITextModel, token: CancellationToken): Promise { - const result = new LinksList(coalesce(lists)); - if (!token.isCancellationRequested) { - return result; - } - result.dispose(); - return new LinksList([]); - }); + return Promise.all(promises).then(() => new LinksList(coalesce(lists))); } diff --git a/src/vs/editor/contrib/links/links.ts b/src/vs/editor/contrib/links/links.ts index a50c984ab6..f4aee3992f 100644 --- a/src/vs/editor/contrib/links/links.ts +++ b/src/vs/editor/contrib/links/links.ts @@ -111,23 +111,6 @@ class LinkOccurrence { } private static _getOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { - const options = { ...this._getBaseOptions(link, useMetaKey, isActive) }; - if (typeof link.tooltip === 'string') { - const message = new MarkdownString().appendText( - platform.isMacintosh - ? useMetaKey - ? nls.localize('links.custom.mac', "Cmd + click to {0}", link.tooltip) - : nls.localize('links.custom.mac.al', "Option + click to {0}", link.tooltip) - : useMetaKey - ? nls.localize('links.custom', "Ctrl + click to {0}", link.tooltip) - : nls.localize('links.custom.al', "Alt + click to {0}", link.tooltip) - ); - options.hoverMessage = message; - } - return options; - } - - private static _getBaseOptions(link: Link, useMetaKey: boolean, isActive: boolean): ModelDecorationOptions { if (link.url && /^command:/i.test(link.url.toString())) { if (useMetaKey) { return (isActive ? decoration.metaCommandActive : decoration.metaCommand); diff --git a/src/vs/editor/contrib/markdown/markdownRenderer.ts b/src/vs/editor/contrib/markdown/markdownRenderer.ts index 531723bbf0..405eb1c8c1 100644 --- a/src/vs/editor/contrib/markdown/markdownRenderer.ts +++ b/src/vs/editor/contrib/markdown/markdownRenderer.ts @@ -78,7 +78,7 @@ export class MarkdownRenderer { } render(markdown: IMarkdownString | undefined): IMarkdownRenderResult { - const disposeables: IDisposable[] = []; + let disposeables: IDisposable[] = []; let element: HTMLElement; if (!markdown) { diff --git a/src/vs/editor/contrib/multicursor/multicursor.ts b/src/vs/editor/contrib/multicursor/multicursor.ts index 7ce401349f..b500bd94d1 100644 --- a/src/vs/editor/contrib/multicursor/multicursor.ts +++ b/src/vs/editor/contrib/multicursor/multicursor.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { RunOnceScheduler } from 'vs/base/common/async'; import { KeyChord, KeyCode, KeyMod } from 'vs/base/common/keyCodes'; -import { Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { EditorAction, ServicesAccessor, registerEditorAction, registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { RevealTarget } from 'vs/editor/common/controller/cursorCommon'; @@ -427,7 +427,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito private readonly _editor: ICodeEditor; private _ignoreSelectionChange: boolean; private _session: MultiCursorSession | null; - private readonly _sessionDispose = this._register(new DisposableStore()); + private _sessionDispose: IDisposable[]; public static get(editor: ICodeEditor): MultiCursorSelectionController { return editor.getContribution(MultiCursorSelectionController.ID); @@ -438,6 +438,7 @@ export class MultiCursorSelectionController extends Disposable implements IEdito this._editor = editor; this._ignoreSelectionChange = false; this._session = null; + this._sessionDispose = []; } public dispose(): void { @@ -467,25 +468,27 @@ export class MultiCursorSelectionController extends Disposable implements IEdito } findController.getState().change(newState, false); - this._sessionDispose.add(this._editor.onDidChangeCursorSelection((e) => { - if (this._ignoreSelectionChange) { - return; - } - this._endSession(); - })); - this._sessionDispose.add(this._editor.onDidBlurEditorText(() => { - this._endSession(); - })); - this._sessionDispose.add(findController.getState().onFindReplaceStateChange((e) => { - if (e.matchCase || e.wholeWord) { + this._sessionDispose = [ + this._editor.onDidChangeCursorSelection((e) => { + if (this._ignoreSelectionChange) { + return; + } this._endSession(); - } - })); + }), + this._editor.onDidBlurEditorText(() => { + this._endSession(); + }), + findController.getState().onFindReplaceStateChange((e) => { + if (e.matchCase || e.wholeWord) { + this._endSession(); + } + }) + ]; } } private _endSession(): void { - this._sessionDispose.clear(); + this._sessionDispose = dispose(this._sessionDispose); if (this._session && this._session.isDisconnectedFromFindController) { const newState: INewFindReplaceState = { wholeWordOverride: FindOptionOverride.NotSet, diff --git a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts index 7b57c130a3..b105b43019 100644 --- a/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts +++ b/src/vs/editor/contrib/parameterHints/parameterHintsWidget.ts @@ -8,7 +8,7 @@ import { domEvent, stop } from 'vs/base/browser/event'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { Event } from 'vs/base/common/event'; -import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./parameterHints'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { IConfigurationChangedEvent } from 'vs/editor/common/config/editorOptions'; @@ -25,12 +25,12 @@ import { ParameterHintsModel, TriggerContext } from 'vs/editor/contrib/parameter const $ = dom.$; -export class ParameterHintsWidget extends Disposable implements IContentWidget, IDisposable { +export class ParameterHintsWidget implements IContentWidget, IDisposable { private static readonly ID = 'editor.widget.parameterHintsWidget'; private readonly markdownRenderer: MarkdownRenderer; - private readonly renderDisposeables = this._register(new DisposableStore()); + private renderDisposeables: IDisposable[]; private model: ParameterHintsModel | null; private readonly keyVisible: IContextKey; private readonly keyMultipleSignatures: IContextKey; @@ -41,6 +41,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, private visible: boolean; private announcedLabel: string | null; private scrollbar: DomScrollableElement; + private disposables: IDisposable[]; // Editor.IContentWidget.allowEditorOverflow allowEditorOverflow = true; @@ -51,14 +52,14 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, @IOpenerService openerService: IOpenerService, @IModeService modeService: IModeService, ) { - super(); this.markdownRenderer = new MarkdownRenderer(editor, modeService, openerService); this.model = new ParameterHintsModel(editor); this.keyVisible = Context.Visible.bindTo(contextKeyService); this.keyMultipleSignatures = Context.MultipleSignatures.bindTo(contextKeyService); this.visible = false; + this.disposables = []; - this._register(this.model.onChangedHints(newParameterHints => { + this.disposables.push(this.model.onChangedHints(newParameterHints => { if (newParameterHints) { this.show(); this.render(newParameterHints); @@ -78,16 +79,16 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, const next = dom.append(buttons, $('.button.next')); const onPreviousClick = stop(domEvent(previous, 'click')); - this._register(onPreviousClick(this.previous, this)); + onPreviousClick(this.previous, this, this.disposables); const onNextClick = stop(domEvent(next, 'click')); - this._register(onNextClick(this.next, this)); + onNextClick(this.next, this, this.disposables); this.overloads = dom.append(wrapper, $('.overloads')); const body = $('.body'); this.scrollbar = new DomScrollableElement(body, {}); - this._register(this.scrollbar); + this.disposables.push(this.scrollbar); wrapper.appendChild(this.scrollbar.getDomNode()); this.signature = dom.append(body, $('.signature')); @@ -98,7 +99,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, this.hide(); this.element.style.userSelect = 'text'; - this._register(this.editor.onDidChangeCursorSelection(e => { + this.disposables.push(this.editor.onDidChangeCursorSelection(e => { if (this.visible) { this.editor.layoutContentWidget(this); } @@ -111,11 +112,11 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, updateFont(); - this._register(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo) - .on(updateFont, null)); + .on(updateFont, null, this.disposables); - this._register(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); + this.disposables.push(this.editor.onDidLayoutChange(e => this.updateMaxHeight())); this.updateMaxHeight(); } @@ -189,7 +190,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, this.renderParameters(code, signature, hints.activeParameter); } - this.renderDisposeables.clear(); + dispose(this.renderDisposeables); + this.renderDisposeables = []; const activeParameter = signature.parameters[hints.activeParameter]; @@ -200,7 +202,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } else { const renderedContents = this.markdownRenderer.render(activeParameter.documentation); dom.addClass(renderedContents.element, 'markdown-docs'); - this.renderDisposeables.add(renderedContents); + this.renderDisposeables.push(renderedContents); documentation.appendChild(renderedContents.element); } dom.append(this.docs, $('p', {}, documentation)); @@ -214,7 +216,7 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } else { const renderedContents = this.markdownRenderer.render(signature.documentation); dom.addClass(renderedContents.element, 'markdown-docs'); - this.renderDisposeables.add(renderedContents); + this.renderDisposeables.push(renderedContents); dom.append(this.docs, renderedContents.element); } @@ -321,7 +323,8 @@ export class ParameterHintsWidget extends Disposable implements IContentWidget, } dispose(): void { - super.dispose(); + this.disposables = dispose(this.disposables); + this.renderDisposeables = dispose(this.renderDisposeables); if (this.model) { this.model.dispose(); diff --git a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css index 250acc6cc2..6d46559fe4 100644 --- a/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css +++ b/src/vs/editor/contrib/referenceSearch/media/peekViewWidget.css @@ -19,6 +19,14 @@ cursor: pointer; } +.monaco-editor .peekview-widget .head .peekview-title .icon { + display: inline-block; + height: 16px; + width: 16px; + vertical-align: text-bottom; + margin-right: 4px; +} + .monaco-editor .peekview-widget .head .peekview-title .dirname:not(:empty) { font-size: 0.9em; margin-left: 0.5em; diff --git a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts index c93dfab479..935a9c68f1 100644 --- a/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/peekViewWidget.ts @@ -85,6 +85,7 @@ export abstract class PeekViewWidget extends ZoneWidget { private _onDidClose = new Emitter(); protected _headElement: HTMLDivElement; + protected _headingIcon: HTMLElement; protected _primaryHeading: HTMLElement; protected _secondaryHeading: HTMLElement; protected _metaHeading: HTMLElement; @@ -154,18 +155,18 @@ export abstract class PeekViewWidget extends ZoneWidget { dom.append(this._headElement, titleElement); dom.addStandardDisposableListener(titleElement, 'click', event => this._onTitleClick(event)); - this._fillTitleIcon(titleElement); + this._headingIcon = dom.$('span'); this._primaryHeading = dom.$('span.filename'); this._secondaryHeading = dom.$('span.dirname'); this._metaHeading = dom.$('span.meta'); - dom.append(titleElement, this._primaryHeading, this._secondaryHeading, this._metaHeading); + dom.append(titleElement, this._headingIcon, this._primaryHeading, this._secondaryHeading, this._metaHeading); const actionsContainer = dom.$('.peekview-actions'); dom.append(this._headElement, actionsContainer); const actionBarOptions = this._getActionBarOptions(); this._actionbarWidget = new ActionBar(actionsContainer, actionBarOptions); - this._disposables.add(this._actionbarWidget); + this._disposables.push(this._actionbarWidget); this._actionbarWidget.push(new Action('peekview.close', nls.localize('label.close', "Close"), 'close-peekview-action', true, () => { this.dispose(); @@ -173,9 +174,6 @@ export abstract class PeekViewWidget extends ZoneWidget { }), { label: false, icon: true }); } - protected _fillTitleIcon(container: HTMLElement): void { - } - protected _getActionBarOptions(): IActionBarOptions { return {}; } @@ -184,6 +182,10 @@ export abstract class PeekViewWidget extends ZoneWidget { // implement me } + public setTitleIcon(iconClassName: string): void { + this._headingIcon.className = iconClassName ? `icon ${iconClassName}` : ''; + } + public setTitle(primaryHeading: string, secondaryHeading?: string): void { this._primaryHeading.innerHTML = strings.escape(primaryHeading); this._primaryHeading.setAttribute('aria-label', primaryHeading); diff --git a/src/vs/editor/contrib/referenceSearch/referencesController.ts b/src/vs/editor/contrib/referenceSearch/referencesController.ts index 5e230bac05..2f714b86bb 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesController.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesController.ts @@ -5,7 +5,7 @@ import * as nls from 'vs/nls'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -32,11 +32,11 @@ export abstract class ReferencesController implements editorCommon.IEditorContri private static readonly ID = 'editor.contrib.referencesController'; - private readonly _disposables = new DisposableStore(); private readonly _editor: ICodeEditor; private _widget: ReferenceWidget | null; private _model: ReferencesModel | null; private _requestIdPool = 0; + private _disposables: IDisposable[] = []; private _ignoreModelChangeEvent = false; private readonly _referenceSearchVisible: IContextKey; @@ -91,8 +91,8 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._referenceSearchVisible.set(true); // close the widget on model/mode changes - this._disposables.add(this._editor.onDidChangeModelLanguage(() => { this.closeWidget(); })); - this._disposables.add(this._editor.onDidChangeModel(() => { + this._disposables.push(this._editor.onDidChangeModelLanguage(() => { this.closeWidget(); })); + this._disposables.push(this._editor.onDidChangeModel(() => { if (!this._ignoreModelChangeEvent) { this.closeWidget(); } @@ -103,7 +103,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._widget.setTitle(nls.localize('labelLoading', "Loading...")); this._widget.show(range); - this._disposables.add(this._widget.onDidClose(() => { + this._disposables.push(this._widget.onDidClose(() => { modelPromise.cancel(); if (this._widget) { this._storageService.store(storageKey, JSON.stringify(this._widget.layoutData), StorageScope.GLOBAL); @@ -112,7 +112,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this.closeWidget(); })); - this._disposables.add(this._widget.onDidSelectReference(event => { + this._disposables.push(this._widget.onDidSelectReference(event => { let { element, kind } = event; switch (kind) { case 'open': @@ -205,7 +205,7 @@ export abstract class ReferencesController implements editorCommon.IEditorContri this._widget = null; } this._referenceSearchVisible.reset(); - this._disposables.clear(); + this._disposables = dispose(this._disposables); if (this._model) { dispose(this._model); this._model = null; diff --git a/src/vs/editor/contrib/referenceSearch/referencesModel.ts b/src/vs/editor/contrib/referenceSearch/referencesModel.ts index f6a651ecc4..f53a84c88a 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesModel.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesModel.ts @@ -6,7 +6,7 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { basename } from 'vs/base/common/resources'; -import { IDisposable, dispose, IReference, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, IReference } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; import { defaultGenerator } from 'vs/base/common/idGenerator'; @@ -14,7 +14,6 @@ import { Range, IRange } from 'vs/editor/common/core/range'; import { Location, LocationLink } from 'vs/editor/common/modes'; import { ITextModelService, ITextEditorModel } from 'vs/editor/common/services/resolverService'; import { Position } from 'vs/editor/common/core/position'; -import { IMatch } from 'vs/base/common/filters'; export class OneReference { readonly id: string; @@ -62,7 +61,7 @@ export class FilePreview implements IDisposable { dispose(this._modelReference); } - preview(range: IRange, n: number = 8): { value: string; highlight: IMatch } | undefined { + preview(range: IRange, n: number = 8): { before: string; inside: string; after: string } | undefined { const model = this._modelReference.object.textEditorModel; if (!model) { @@ -74,14 +73,13 @@ export class FilePreview implements IDisposable { const beforeRange = new Range(startLineNumber, word.startColumn, startLineNumber, startColumn); const afterRange = new Range(endLineNumber, endColumn, endLineNumber, Number.MAX_VALUE); - const before = model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty); - const inside = model.getValueInRange(range); - const after = model.getValueInRange(afterRange).replace(/\s+$/, strings.empty); - - return { - value: before + inside + after, - highlight: { start: before.length, end: before.length + inside.length } + const ret = { + before: model.getValueInRange(beforeRange).replace(/^\s+/, strings.empty), + inside: model.getValueInRange(range), + after: model.getValueInRange(afterRange).replace(/\s+$/, strings.empty) }; + + return ret; } } @@ -166,7 +164,7 @@ export class FileReferences implements IDisposable { export class ReferencesModel implements IDisposable { - private readonly _disposables = new DisposableStore(); + private readonly _disposables: IDisposable[]; readonly groups: FileReferences[] = []; readonly references: OneReference[] = []; @@ -174,7 +172,7 @@ export class ReferencesModel implements IDisposable { readonly onDidChangeReferenceRange: Event = this._onDidChangeReferenceRange.event; constructor(references: LocationLink[]) { - + this._disposables = []; // grouping and sorting const [providersFirst] = references; references.sort(ReferencesModel._compareReferences); @@ -192,7 +190,7 @@ export class ReferencesModel implements IDisposable { || !Range.equalsRange(ref.range, current.children[current.children.length - 1].range)) { let oneRef = new OneReference(current, ref.targetSelectionRange || ref.range, providersFirst === ref); - this._disposables.add(oneRef.onRefChanged((e) => this._onDidChangeReferenceRange.fire(e))); + this._disposables.push(oneRef.onRefChanged((e) => this._onDidChangeReferenceRange.fire(e))); this.references.push(oneRef); current.children.push(oneRef); } @@ -282,8 +280,9 @@ export class ReferencesModel implements IDisposable { dispose(): void { dispose(this.groups); - this._disposables.dispose(); + dispose(this._disposables); this.groups.length = 0; + this._disposables.length = 0; } private static _compareReferences(a: Location, b: Location): number { diff --git a/src/vs/editor/contrib/referenceSearch/referencesTree.ts b/src/vs/editor/contrib/referenceSearch/referencesTree.ts index d10cbd6430..40778caf2d 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesTree.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesTree.ts @@ -15,6 +15,7 @@ import * as dom from 'vs/base/browser/dom'; import { localize } from 'vs/nls'; import { getBaseLabel } from 'vs/base/common/labels'; import { dirname, basename } from 'vs/base/common/resources'; +import { escape } from 'vs/base/common/strings'; import { Disposable } from 'vs/base/common/lifecycle'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; @@ -22,7 +23,6 @@ import { IListVirtualDelegate, IKeyboardNavigationLabelProvider, IIdentityProvid import { IKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { FuzzyScore, createMatches, IMatch } from 'vs/base/common/filters'; -import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; //#region data source @@ -82,14 +82,8 @@ export class StringRepresentationProvider implements IKeyboardNavigationLabelPro constructor(@IKeybindingService private readonly _keybindingService: IKeybindingService) { } getKeyboardNavigationLabel(element: TreeElement): { toString(): string; } { - if (element instanceof OneReference) { - const { preview } = element.parent; - const parts = preview && preview.preview(element.range); - if (parts) { - return parts.value; - } - } - // FileReferences or unresolved OneReference + // todo@joao `OneReference` elements are lazy and their "real" label + // isn't known yet return basename(element.uri); } @@ -167,29 +161,31 @@ export class FileReferencesRenderer implements ITreeRenderer, index: number, templateData: OneReferenceTemplate): void { - templateData.set(node.element, node.filterData); + renderElement(element: ITreeNode, index: number, templateData: OneReferenceTemplate): void { + templateData.set(element.element); } disposeTemplate(): void { + // } } diff --git a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts index 5f15ead33f..ee15970a60 100644 --- a/src/vs/editor/contrib/referenceSearch/referencesWidget.ts +++ b/src/vs/editor/contrib/referenceSearch/referencesWidget.ts @@ -8,7 +8,7 @@ import { IMouseEvent } from 'vs/base/browser/mouseEvent'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Color } from 'vs/base/common/color'; import { Emitter, Event } from 'vs/base/common/event'; -import { dispose, IDisposable, IReference, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, IReference } from 'vs/base/common/lifecycle'; import { Schemas } from 'vs/base/common/network'; import { basenameOrAuthority, dirname } from 'vs/base/common/resources'; import 'vs/css!./media/referencesWidget'; @@ -47,22 +47,22 @@ class DecorationsManager implements IDisposable { private _decorations = new Map(); private _decorationIgnoreSet = new Set(); - private readonly _callOnDispose = new DisposableStore(); - private readonly _callOnModelChange = new DisposableStore(); + private _callOnDispose: IDisposable[] = []; + private _callOnModelChange: IDisposable[] = []; constructor(private _editor: ICodeEditor, private _model: ReferencesModel) { - this._callOnDispose.add(this._editor.onDidChangeModel(() => this._onModelChanged())); + this._callOnDispose.push(this._editor.onDidChangeModel(() => this._onModelChanged())); this._onModelChanged(); } public dispose(): void { - this._callOnModelChange.dispose(); - this._callOnDispose.dispose(); + this._callOnModelChange = dispose(this._callOnModelChange); + this._callOnDispose = dispose(this._callOnDispose); this.removeDecorations(); } private _onModelChanged(): void { - this._callOnModelChange.clear(); + this._callOnModelChange = dispose(this._callOnModelChange); const model = this._editor.getModel(); if (model) { for (const ref of this._model.groups) { @@ -78,7 +78,7 @@ class DecorationsManager implements IDisposable { if (!this._editor.hasModel()) { return; } - this._callOnModelChange.add(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged())); + this._callOnModelChange.push(this._editor.getModel().onDidChangeDecorations((event) => this._onDecorationChanged())); const newDecorations: IModelDeltaDecoration[] = []; const newDecorationsActualIndex: number[] = []; @@ -194,8 +194,8 @@ export class ReferenceWidget extends PeekViewWidget { private _model: ReferencesModel | undefined; private _decorationsManager: DecorationsManager; - private readonly _disposeOnNewModel = new DisposableStore(); - private readonly _callOnDispose = new DisposableStore(); + private _disposeOnNewModel: IDisposable[] = []; + private _callOnDispose: IDisposable[] = []; private _onDidSelectReference = new Emitter(); private _tree: WorkbenchAsyncDataTree; @@ -222,19 +222,15 @@ export class ReferenceWidget extends PeekViewWidget { super(editor, { showFrame: false, showArrow: true, isResizeable: true, isAccessible: true }); this._applyTheme(themeService.getTheme()); - this._callOnDispose.add(themeService.onThemeChange(this._applyTheme.bind(this))); + this._callOnDispose.push(themeService.onThemeChange(this._applyTheme.bind(this))); this._peekViewService.addExclusiveWidget(editor, this); this.create(); } dispose(): void { this.setModel(undefined); - this._callOnDispose.dispose(); - this._disposeOnNewModel.dispose(); - dispose(this._preview); - dispose(this._previewNotAvailableMessage); - dispose(this._tree); - dispose(this._previewModelReference); + this._callOnDispose = dispose(this._callOnDispose); + dispose(this._preview, this._previewNotAvailableMessage, this._tree, this._previewModelReference); this._splitView.dispose(); super.dispose(); } @@ -348,11 +344,11 @@ export class ReferenceWidget extends PeekViewWidget { } }, Sizing.Distribute); - this._disposables.add(this._splitView.onDidSashChange(() => { + this._splitView.onDidSashChange(() => { if (this._dim.width) { this.layoutData.ratio = this._splitView.getViewSize(0) / this._dim.width; } - }, undefined)); + }, undefined, this._disposables); // listen on selection and focus let onEvent = (element: any, kind: 'show' | 'goto' | 'side') => { @@ -425,7 +421,7 @@ export class ReferenceWidget extends PeekViewWidget { public setModel(newModel: ReferencesModel | undefined): Promise { // clean up - this._disposeOnNewModel.clear(); + this._disposeOnNewModel = dispose(this._disposeOnNewModel); this._model = newModel; if (this._model) { return this._onNewModel(); @@ -447,13 +443,13 @@ export class ReferenceWidget extends PeekViewWidget { dom.hide(this._messageContainer); this._decorationsManager = new DecorationsManager(this._preview, this._model); - this._disposeOnNewModel.add(this._decorationsManager); + this._disposeOnNewModel.push(this._decorationsManager); // listen on model changes - this._disposeOnNewModel.add(this._model.onDidChangeReferenceRange(reference => this._tree.rerender(reference))); + this._disposeOnNewModel.push(this._model.onDidChangeReferenceRange(reference => this._tree.rerender(reference))); // listen on editor - this._disposeOnNewModel.add(this._preview.onMouseDown(e => { + this._disposeOnNewModel.push(this._preview.onMouseDown(e => { const { event, target } = e; if (event.detail !== 2) { return; @@ -570,7 +566,7 @@ export const peekViewEditorMatchHighlightBorder = registerColor('peekViewEditor. registerThemingParticipant((theme, collector) => { const findMatchHighlightColor = theme.getColor(peekViewResultsMatchHighlight); if (findMatchHighlightColor) { - collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight { background-color: ${findMatchHighlightColor}; }`); + collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch { background-color: ${findMatchHighlightColor}; }`); } const referenceHighlightColor = theme.getColor(peekViewEditorMatchHighlight); if (referenceHighlightColor) { @@ -582,7 +578,7 @@ registerThemingParticipant((theme, collector) => { } const hcOutline = theme.getColor(activeContrastBorder); if (hcOutline) { - collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch .highlight { border: 1px dotted ${hcOutline}; box-sizing: border-box; }`); + collector.addRule(`.monaco-editor .reference-zone-widget .ref-tree .referenceMatch { border: 1px dotted ${hcOutline}; box-sizing: border-box; }`); } const resultsBackground = theme.getColor(peekViewResultsBackground); if (resultsBackground) { diff --git a/src/vs/editor/contrib/rename/rename.ts b/src/vs/editor/contrib/rename/rename.ts index 2069ca47a5..e1d6bed0c4 100644 --- a/src/vs/editor/contrib/rename/rename.ts +++ b/src/vs/editor/contrib/rename/rename.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import { illegalArgument, onUnexpectedError } from 'vs/base/common/errors'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { registerEditorAction, registerEditorContribution, ServicesAccessor, EditorAction, EditorCommand, registerEditorCommand, registerDefaultLanguageCommand } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; @@ -114,7 +114,7 @@ class RenameController extends Disposable implements IEditorContribution { private readonly editor: ICodeEditor, @INotificationService private readonly _notificationService: INotificationService, @IBulkEditService private readonly _bulkEditService: IBulkEditService, - @ILocalProgressService private readonly _progressService: ILocalProgressService, + @IProgressService private readonly _progressService: IProgressService, @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IThemeService private readonly _themeService: IThemeService, ) { diff --git a/src/vs/editor/contrib/rename/renameInputField.ts b/src/vs/editor/contrib/rename/renameInputField.ts index 3b6042c5f9..79961cb674 100644 --- a/src/vs/editor/contrib/rename/renameInputField.ts +++ b/src/vs/editor/contrib/rename/renameInputField.ts @@ -3,8 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import 'vs/css!./renameInputField'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { ContentWidgetPositionPreference, ICodeEditor, IContentWidget, IContentWidgetPosition } from 'vs/editor/browser/editorBrowser'; import { Position } from 'vs/editor/common/core/position'; import { IRange, Range } from 'vs/editor/common/core/range'; @@ -24,10 +24,10 @@ export class RenameInputField implements IContentWidget, IDisposable { private _inputField: HTMLInputElement; private _visible: boolean; private readonly _visibleContextKey: IContextKey; - private readonly _disposables = new DisposableStore(); + private _disposables: IDisposable[] = []; // Editor.IContentWidget.allowEditorOverflow - allowEditorOverflow: boolean = true; + public allowEditorOverflow: boolean = true; constructor( editor: ICodeEditor, @@ -39,13 +39,13 @@ export class RenameInputField implements IContentWidget, IDisposable { this._editor = editor; this._editor.addContentWidget(this); - this._disposables.add(editor.onDidChangeConfiguration(e => { + this._disposables.push(editor.onDidChangeConfiguration(e => { if (e.fontInfo) { this.updateFont(); } })); - this._disposables.add(themeService.onThemeChange(theme => this.onThemeChange(theme))); + this._disposables.push(themeService.onThemeChange(theme => this.onThemeChange(theme))); } private onThemeChange(theme: ITheme): void { @@ -53,7 +53,7 @@ export class RenameInputField implements IContentWidget, IDisposable { } public dispose(): void { - this._disposables.dispose(); + this._disposables = dispose(this._disposables); this._editor.removeContentWidget(this); } @@ -138,9 +138,9 @@ export class RenameInputField implements IContentWidget, IDisposable { this._inputField.setAttribute('selectionEnd', selectionEnd.toString()); this._inputField.size = Math.max((where.endColumn - where.startColumn) * 1.1, 20); - const disposeOnDone = new DisposableStore(); + const disposeOnDone: IDisposable[] = []; const always = () => { - disposeOnDone.dispose(); + dispose(disposeOnDone); this._hide(); }; @@ -172,8 +172,8 @@ export class RenameInputField implements IContentWidget, IDisposable { } }; - disposeOnDone.add(this._editor.onDidChangeCursorSelection(onCursorChanged)); - disposeOnDone.add(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); + disposeOnDone.push(this._editor.onDidChangeCursorSelection(onCursorChanged)); + disposeOnDone.push(this._editor.onDidBlurEditorWidget(() => this.cancelInput(false))); this._show(); diff --git a/src/vs/editor/contrib/smartSelect/bracketSelections.ts b/src/vs/editor/contrib/smartSelect/bracketSelections.ts index cabec83178..6fd74cf046 100644 --- a/src/vs/editor/contrib/smartSelect/bracketSelections.ts +++ b/src/vs/editor/contrib/smartSelect/bracketSelections.ts @@ -115,8 +115,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { } const innerBracket = Range.fromPositions(bracket.range.getEndPosition(), closing!.getStartPosition()); const outerBracket = Range.fromPositions(bracket.range.getStartPosition(), closing!.getEndPosition()); - bucket.push({ range: innerBracket }); - bucket.push({ range: outerBracket }); + bucket.push({ range: innerBracket, kind: 'statement.brackets' }); + bucket.push({ range: outerBracket, kind: 'statement.brackets.full' }); BracketSelectionRangeProvider._addBracketLeading(model, outerBracket, bucket); } } @@ -135,8 +135,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { const startLine = bracket.startLineNumber; const column = model.getLineFirstNonWhitespaceColumn(startLine); if (column !== 0 && column !== bracket.startColumn) { - bucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()) }); - bucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()) }); + bucket.push({ range: Range.fromPositions(new Position(startLine, column), bracket.getEndPosition()), kind: 'statement.brackets.leading' }); + bucket.push({ range: Range.fromPositions(new Position(startLine, 1), bracket.getEndPosition()), kind: 'statement.brackets.leading.full' }); } // xxxxxxxx @@ -147,8 +147,8 @@ export class BracketSelectionRangeProvider implements SelectionRangeProvider { if (aboveLine > 0) { const column = model.getLineFirstNonWhitespaceColumn(aboveLine); if (column === bracket.startColumn && column !== model.getLineLastNonWhitespaceColumn(aboveLine)) { - bucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()) }); - bucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()) }); + bucket.push({ range: Range.fromPositions(new Position(aboveLine, column), bracket.getEndPosition()), kind: 'statement.brackets.leading' }); + bucket.push({ range: Range.fromPositions(new Position(aboveLine, 1), bracket.getEndPosition()), kind: 'statement.brackets.leading.full' }); } } } diff --git a/src/vs/editor/contrib/smartSelect/smartSelect.ts b/src/vs/editor/contrib/smartSelect/smartSelect.ts index ab36647627..2d2bf8140e 100644 --- a/src/vs/editor/contrib/smartSelect/smartSelect.ts +++ b/src/vs/editor/contrib/smartSelect/smartSelect.ts @@ -284,12 +284,12 @@ export function provideSelectionRanges(model: ITextModel, positions: Position[], if (cur.startLineNumber !== prev.startLineNumber || cur.endLineNumber !== prev.endLineNumber) { // add line/block range without leading/failing whitespace const rangeNoWhitespace = new Range(prev.startLineNumber, model.getLineFirstNonWhitespaceColumn(prev.startLineNumber), prev.endLineNumber, model.getLineLastNonWhitespaceColumn(prev.endLineNumber)); - if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev) && cur.containsRange(rangeNoWhitespace) && !cur.equalsRange(rangeNoWhitespace)) { + if (rangeNoWhitespace.containsRange(prev) && !rangeNoWhitespace.equalsRange(prev)) { oneRangesWithTrivia.push(rangeNoWhitespace); } // add line/block range const rangeFull = new Range(prev.startLineNumber, 1, prev.endLineNumber, model.getLineMaxColumn(prev.endLineNumber)); - if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace) && cur.containsRange(rangeFull) && !cur.equalsRange(rangeFull)) { + if (rangeFull.containsRange(prev) && !rangeFull.equalsRange(rangeNoWhitespace)) { oneRangesWithTrivia.push(rangeFull); } } diff --git a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts index 4cbba32e1a..240209c453 100644 --- a/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts +++ b/src/vs/editor/contrib/smartSelect/test/smartSelect.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { URI } from 'vs/base/common/uri'; import { Range, IRange } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; -import { LanguageIdentifier, SelectionRangeProvider, SelectionRangeRegistry } from 'vs/editor/common/modes'; +import { LanguageIdentifier, SelectionRangeProvider } from 'vs/editor/common/modes'; import { MockMode, StaticLanguageSelector } from 'vs/editor/test/common/mocks/mockMode'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; @@ -320,25 +320,4 @@ suite('SmartSelect', () => { new Range(1, 1, 1, 21), ); }); - - test('Smart select: only add line ranges if they’re contained by the next range #73850', async function () { - - const reg = SelectionRangeRegistry.register('*', { - provideSelectionRanges() { - return [[ - { range: { startLineNumber: 1, startColumn: 10, endLineNumber: 1, endColumn: 11 } }, - { range: { startLineNumber: 1, startColumn: 10, endLineNumber: 3, endColumn: 2 } }, - { range: { startLineNumber: 1, startColumn: 1, endLineNumber: 3, endColumn: 2 } }, - ]]; - } - }); - - await assertGetRangesToPosition(['type T = {', '\tx: number', '}'], 1, 10, [ - new Range(1, 1, 3, 2), // all - new Range(1, 10, 3, 2), // { ... } - new Range(1, 10, 1, 11), // { - ]); - - reg.dispose(); - }); }); diff --git a/src/vs/editor/contrib/smartSelect/wordSelections.ts b/src/vs/editor/contrib/smartSelect/wordSelections.ts index 78c7a7252e..12ff057ef4 100644 --- a/src/vs/editor/contrib/smartSelect/wordSelections.ts +++ b/src/vs/editor/contrib/smartSelect/wordSelections.ts @@ -20,7 +20,7 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { this._addInWordRanges(bucket, model, position); this._addWordRanges(bucket, model, position); this._addWhitespaceLine(bucket, model, position); - bucket.push({ range: model.getFullModelRange() }); + bucket.push({ range: model.getFullModelRange(), kind: 'statement.all' }); } return result; } @@ -65,14 +65,14 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { } if (start < end) { - bucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end) }); + bucket.push({ range: new Range(pos.lineNumber, startColumn + start, pos.lineNumber, startColumn + end), kind: 'statement.word.part' }); } } private _addWordRanges(bucket: SelectionRange[], model: ITextModel, pos: Position): void { const word = model.getWordAtPosition(pos); if (word) { - bucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn) }); + bucket.push({ range: new Range(pos.lineNumber, word.startColumn, pos.lineNumber, word.endColumn), kind: 'statement.word' }); } } @@ -81,7 +81,7 @@ export class WordSelectionRangeProvider implements SelectionRangeProvider { && model.getLineFirstNonWhitespaceColumn(pos.lineNumber) === 0 && model.getLineLastNonWhitespaceColumn(pos.lineNumber) === 0 ) { - bucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)) }); + bucket.push({ range: new Range(pos.lineNumber, 1, pos.lineNumber, model.getLineMaxColumn(pos.lineNumber)), kind: 'statement.line' }); } } } diff --git a/src/vs/editor/contrib/snippet/snippetSession.ts b/src/vs/editor/contrib/snippet/snippetSession.ts index a955b22933..e8745ff99e 100644 --- a/src/vs/editor/contrib/snippet/snippetSession.ts +++ b/src/vs/editor/contrib/snippet/snippetSession.ts @@ -17,7 +17,7 @@ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { optional } from 'vs/platform/instantiation/common/instantiation'; -import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet, Marker } from './snippetParser'; +import { Choice, Placeholder, SnippetParser, Text, TextmateSnippet } from './snippetParser'; import { ClipboardBasedVariableResolver, CompositeSnippetVariableResolver, ModelBasedVariableResolver, SelectionBasedVariableResolver, TimeBasedVariableResolver, CommentBasedVariableResolver, WorkspaceBasedVariableResolver } from './snippetVariables'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import * as colors from 'vs/platform/theme/common/colorRegistry'; @@ -122,14 +122,14 @@ export class OneSnippet { } } - let couldSkipThisPlaceholder = false; + let skipThisPlaceholder = false; if (fwd === true && this._placeholderGroupsIdx < this._placeholderGroups.length - 1) { this._placeholderGroupsIdx += 1; - couldSkipThisPlaceholder = true; + skipThisPlaceholder = true; } else if (fwd === false && this._placeholderGroupsIdx > 0) { this._placeholderGroupsIdx -= 1; - couldSkipThisPlaceholder = true; + skipThisPlaceholder = true; } else { // the selection of the current placeholder might @@ -154,7 +154,7 @@ export class OneSnippet { // consider to skip this placeholder index when the decoration // range is empty but when the placeholder wasn't. that's a strong // hint that the placeholder has been deleted. (all placeholder must match this) - couldSkipThisPlaceholder = couldSkipThisPlaceholder && this._hasPlaceholderBeenCollapsed(placeholder); + skipThisPlaceholder = skipThisPlaceholder && (range.isEmpty() && placeholder.toString().length > 0); accessor.changeDecorationOptions(id, placeholder.isFinalTabstop ? OneSnippet._decor.activeFinal : OneSnippet._decor.active); activePlaceholders.add(placeholder); @@ -177,25 +177,7 @@ export class OneSnippet { return selections; })!; - return !couldSkipThisPlaceholder ? newSelections : this.move(fwd); - } - - private _hasPlaceholderBeenCollapsed(placeholder: Placeholder): boolean { - // A placeholder is empty when it wasn't empty when authored but - // when its tracking decoration is empty. This also applies to all - // potential parent placeholders - let marker: Marker | undefined = placeholder; - while (marker) { - if (marker instanceof Placeholder) { - const id = this._placeholderDecorations.get(marker)!; - const range = this._editor.getModel().getDecorationRange(id)!; - if (range.isEmpty() && marker.toString().length > 0) { - return true; - } - } - marker = marker.parent; - } - return false; + return !skipThisPlaceholder ? newSelections : this.move(fwd); } get isAtFirstPlaceholder() { diff --git a/src/vs/editor/contrib/snippet/test/snippetController2.test.ts b/src/vs/editor/contrib/snippet/test/snippetController2.test.ts index 1c9c0dcbcf..6d792a9a58 100644 --- a/src/vs/editor/contrib/snippet/test/snippetController2.test.ts +++ b/src/vs/editor/contrib/snippet/test/snippetController2.test.ts @@ -410,22 +410,4 @@ suite('SnippetController2', function () { ctrl.insert('export default $1'); assertContextKeys(contextKeys, true, false, true); }); - - test('Optional tabstop in snippets #72358', function () { - const ctrl = new SnippetController2(editor, logService, contextKeys); - model.setValue(''); - editor.setSelection(new Selection(1, 1, 1, 1)); - - ctrl.insert('${1:prop: {$2\\},}\nmore$0'); - assertContextKeys(contextKeys, true, false, true); - - assertSelections(editor, new Selection(1, 1, 1, 10)); - editor.trigger('test', Handler.Cut, {}); - - assertSelections(editor, new Selection(1, 1, 1, 1)); - - ctrl.next(); - assertSelections(editor, new Selection(2, 5, 2, 5)); - assertContextKeys(contextKeys, false, false, false); - }); }); diff --git a/src/vs/editor/contrib/suggest/suggest.ts b/src/vs/editor/contrib/suggest/suggest.ts index 84dc94d085..463f8d3df4 100644 --- a/src/vs/editor/contrib/suggest/suggest.ts +++ b/src/vs/editor/contrib/suggest/suggest.ts @@ -16,7 +16,6 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Range } from 'vs/editor/common/core/range'; import { FuzzyScore } from 'vs/base/common/filters'; -import { isDisposable, DisposableStore } from 'vs/base/common/lifecycle'; export const Context = { Visible: new RawContextKey('suggestWidgetVisible', false), @@ -122,6 +121,7 @@ export function provideSuggestionItems( token: CancellationToken = CancellationToken.None ): Promise { + const allSuggestions: CompletionItem[] = []; const wordUntil = model.getWordUntilPosition(position); const defaultRange = new Range(position.lineNumber, wordUntil.startColumn, position.lineNumber, wordUntil.endColumn); @@ -135,12 +135,9 @@ export function provideSuggestionItems( supports.unshift([_snippetSuggestSupport]); } - const allSuggestions: CompletionItem[] = []; - const disposables = new DisposableStore(); - let hasResult = false; - // add suggestions from contributed providers - providers are ordered in groups of // equal score and once a group produces a result the process stops + let hasResult = false; const factory = supports.map(supports => () => { // for each support in the group ask for suggestions return Promise.all(supports.map(provider => { @@ -165,9 +162,6 @@ export function provideSuggestionItems( allSuggestions.push(new CompletionItem(position, suggestion, container, provider, model)); } } - if (isDisposable(container)) { - disposables.add(container); - } } if (len !== allSuggestions.length && provider !== _snippetSuggestSupport) { @@ -183,7 +177,6 @@ export function provideSuggestionItems( return hasResult || token.isCancellationRequested; }).then(() => { if (token.isCancellationRequested) { - disposables.dispose(); return Promise.reject(canceled()); } return allSuggestions.sort(getSuggestionComparator(options.snippetSortOrder)); @@ -251,35 +244,29 @@ export function getSuggestionComparator(snippetConfig: SnippetSortOrder): (a: Co return _snippetComparators.get(snippetConfig)!; } -registerDefaultLanguageCommand('_executeCompletionItemProvider', async (model, position, args) => { +registerDefaultLanguageCommand('_executeCompletionItemProvider', (model, position, args) => { const result: modes.CompletionList = { incomplete: false, suggestions: [] }; - const disposables = new DisposableStore(); - const resolving: Promise[] = []; - const maxItemsToResolve = args['maxItemsToResolve'] || 0; + let resolving: Promise[] = []; + let maxItemsToResolve = args['maxItemsToResolve'] || 0; - const items = await provideSuggestionItems(model, position); - for (const item of items) { - if (resolving.length < maxItemsToResolve) { - resolving.push(item.resolve(CancellationToken.None)); + return provideSuggestionItems(model, position).then(items => { + for (const item of items) { + if (resolving.length < maxItemsToResolve) { + resolving.push(item.resolve(CancellationToken.None)); + } + result.incomplete = result.incomplete || item.container.incomplete; + result.suggestions.push(item.completion); } - result.incomplete = result.incomplete || item.container.incomplete; - result.suggestions.push(item.completion); - if (isDisposable(item.container)) { - disposables.add(item.container); - } - } - - try { - await Promise.all(resolving); + }).then(() => { + return Promise.all(resolving); + }).then(() => { return result; - } finally { - disposables.dispose(); - } + }); }); interface SuggestController extends IEditorContribution { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 6104caaaac..1bf00c62e9 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -9,8 +9,8 @@ import { createMatches } from 'vs/base/common/filters'; import * as strings from 'vs/base/common/strings'; import { Event, Emitter } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass, addDisposableListener } from 'vs/base/browser/dom'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; +import { addClass, append, $, hide, removeClass, show, toggleClass, getDomNodePagePosition, hasClass } from 'vs/base/browser/dom'; import { IListVirtualDelegate, IListEvent, IListRenderer, IListMouseEvent } from 'vs/base/browser/ui/list/list'; import { List } from 'vs/base/browser/ui/list/listWidget'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; @@ -103,9 +103,7 @@ class Renderer implements IListRenderer renderTemplate(container: HTMLElement): ISuggestionTemplateData { const data = Object.create(null); - const disposables = new DisposableStore(); - data.disposables = [disposables]; - + data.disposables = []; data.root = container; addClass(data.root, 'show-file-icons'); @@ -116,7 +114,7 @@ class Renderer implements IListRenderer const main = append(text, $('.main')); data.iconLabel = new IconLabel(main, { supportHighlights: true }); - disposables.add(data.iconLabel); + data.disposables.push(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); @@ -144,9 +142,9 @@ class Renderer implements IListRenderer configureFont(); - disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo || e.contribInfo) - .on(configureFont, null)); + .on(configureFont, null, data.disposables); return data; } @@ -401,7 +399,6 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate(); private onDidFocusEmitter = new Emitter(); private onDidHideEmitter = new Emitter(); private onDidShowEmitter = new Emitter(); + readonly onDidSelect: Event = this.onDidSelectEmitter.event; readonly onDidFocus: Event = this.onDidFocusEmitter.event; readonly onDidHide: Event = this.onDidHideEmitter.event; @@ -466,11 +464,6 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (e.target === this.element) { - this.hideWidget(); - } - })); this.messageElement = append(this.element, $('.message')); this.listElement = append(this.element, $('.tree')); @@ -487,7 +480,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate this.onListFocus(e)), this.editor.onDidChangeCursorSelection(() => this.onCursorSelectionChanged()), this.editor.onDidChangeConfiguration(e => e.contribInfo && applyIconStyle()) - ); + ]; this.suggestWidgetVisible = SuggestContext.Visible.bindTo(contextKeyService); this.suggestWidgetMultipleSuggestions = SuggestContext.MultipleSuggestions.bindTo(contextKeyService); @@ -1159,7 +1152,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate('atEndOfWord', false); private readonly _ckAtEnd: IContextKey; + private readonly _confListener: IDisposable; private _enabled: boolean; private _selectionListener?: IDisposable; @@ -20,15 +21,13 @@ export class WordContextKey extends Disposable { private readonly _editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, ) { - super(); this._ckAtEnd = WordContextKey.AtEnd.bindTo(contextKeyService); - this._register(this._editor.onDidChangeConfiguration(e => e.contribInfo && this._update())); + this._confListener = this._editor.onDidChangeConfiguration(e => e.contribInfo && this._update()); this._update(); } dispose(): void { - super.dispose(); - dispose(this._selectionListener); + dispose(this._confListener, this._selectionListener); this._ckAtEnd.reset(); } diff --git a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts index 75f4a5a131..6a36320415 100644 --- a/src/vs/editor/contrib/zoneWidget/zoneWidget.ts +++ b/src/vs/editor/contrib/zoneWidget/zoneWidget.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash, SashState } from 'vs/base/browser/ui/sash/sash'; import { Color, RGBA } from 'vs/base/common/color'; import { IdGenerator } from 'vs/base/common/idGenerator'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, IViewZone, IViewZoneChangeAccessor } from 'vs/editor/browser/editorBrowser'; import { EditorLayoutInfo } from 'vs/editor/common/config/editorOptions'; @@ -165,7 +165,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { private _positionMarkerId: string[] = []; protected _viewZone: ViewZoneDelegate | null; - protected readonly _disposables = new DisposableStore(); + protected _disposables: IDisposable[] = []; public container: HTMLElement; public domNode: HTMLElement; @@ -183,7 +183,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this.domNode.setAttribute('role', 'presentation'); } - this._disposables.add(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => { + this._disposables.push(this.editor.onDidLayoutChange((info: EditorLayoutInfo) => { const width = this._getWidth(info); this.domNode.style.width = width + 'px'; this.domNode.style.left = this._getLeft(info) + 'px'; @@ -193,7 +193,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { public dispose(): void { - this._disposables.dispose(); + dispose(this._disposables); if (this._overlayWidget) { this.editor.removeOverlayWidget(this._overlayWidget); @@ -225,7 +225,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { this.domNode.appendChild(this.container); if (this.options.showArrow) { this._arrow = new Arrow(this.editor); - this._disposables.add(this._arrow); + this._disposables.push(this._arrow); } this._fillContainer(this.container); this._initSash(); @@ -470,10 +470,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { // --- sash private _initSash(): void { - if (this._resizeSash) { - return; - } - this._resizeSash = this._disposables.add(new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL })); + this._resizeSash = new Sash(this.domNode, this, { orientation: Orientation.HORIZONTAL }); if (!this.options.isResizeable) { this._resizeSash.hide(); @@ -481,7 +478,7 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } let data: { startY: number; heightInLines: number; } | undefined; - this._disposables.add(this._resizeSash.onDidStart((e: ISashEvent) => { + this._disposables.push(this._resizeSash.onDidStart((e: ISashEvent) => { if (this._viewZone) { data = { startY: e.startY, @@ -490,11 +487,11 @@ export abstract class ZoneWidget implements IHorizontalSashLayoutProvider { } })); - this._disposables.add(this._resizeSash.onDidEnd(() => { + this._disposables.push(this._resizeSash.onDidEnd(() => { data = undefined; })); - this._disposables.add(this._resizeSash.onDidChange((evt: ISashEvent) => { + this._disposables.push(this._resizeSash.onDidChange((evt: ISashEvent) => { if (data) { let lineDelta = (evt.currentY - data.startY) / this.editor.getConfiguration().lineHeight; let roundedLineDelta = lineDelta < 0 ? Math.ceil(lineDelta) : Math.floor(lineDelta); diff --git a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts index 2ff84f1def..ad74dc5e01 100644 --- a/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts +++ b/src/vs/editor/standalone/browser/iPadShowKeyboard/iPadShowKeyboard.ts @@ -6,23 +6,24 @@ import 'vs/css!./iPadShowKeyboard'; import * as browser from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditor, IOverlayWidget, IOverlayWidgetPosition, OverlayWidgetPositionPreference } from 'vs/editor/browser/editorBrowser'; import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; -export class IPadShowKeyboard extends Disposable implements IEditorContribution { +export class IPadShowKeyboard implements IEditorContribution { private static readonly ID = 'editor.contrib.iPadShowKeyboard'; private readonly editor: ICodeEditor; private widget: ShowKeyboardWidget | null; + private toDispose: IDisposable[]; constructor(editor: ICodeEditor) { - super(); this.editor = editor; + this.toDispose = []; if (browser.isIPad) { - this._register(editor.onDidChangeConfiguration(() => this.update())); + this.toDispose.push(editor.onDidChangeConfiguration(() => this.update())); this.update(); } } @@ -47,7 +48,7 @@ export class IPadShowKeyboard extends Disposable implements IEditorContribution } public dispose(): void { - super.dispose(); + this.toDispose = dispose(this.toDispose); if (this.widget) { this.widget.dispose(); this.widget = null; @@ -55,24 +56,25 @@ export class IPadShowKeyboard extends Disposable implements IEditorContribution } } -class ShowKeyboardWidget extends Disposable implements IOverlayWidget { +class ShowKeyboardWidget implements IOverlayWidget { private static readonly ID = 'editor.contrib.ShowKeyboardWidget'; private readonly editor: ICodeEditor; private readonly _domNode: HTMLElement; + private _toDispose: IDisposable[]; constructor(editor: ICodeEditor) { - super(); this.editor = editor; this._domNode = document.createElement('textarea'); this._domNode.className = 'iPadShowKeyboard'; - this._register(dom.addDisposableListener(this._domNode, 'touchstart', (e) => { + this._toDispose = []; + this._toDispose.push(dom.addDisposableListener(this._domNode, 'touchstart', (e) => { this.editor.focus(); })); - this._register(dom.addDisposableListener(this._domNode, 'focus', (e) => { + this._toDispose.push(dom.addDisposableListener(this._domNode, 'focus', (e) => { this.editor.focus(); })); @@ -81,7 +83,7 @@ class ShowKeyboardWidget extends Disposable implements IOverlayWidget { public dispose(): void { this.editor.removeOverlayWidget(this); - super.dispose(); + this._toDispose = dispose(this._toDispose); } // ----- IOverlayWidget API diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index b03c4d4006..acfb20217b 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -8,7 +8,7 @@ import * as dom from 'vs/base/browser/dom'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { Emitter, Event } from 'vs/base/common/event'; import { Keybinding, ResolvedKeybinding, SimpleKeybinding, createKeybinding } from 'vs/base/common/keyCodes'; -import { IDisposable, IReference, ImmortalReference, toDisposable, DisposableStore, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, IReference, ImmortalReference, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { OS, isLinux, isMacintosh } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { URI } from 'vs/base/common/uri'; @@ -25,7 +25,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { IResolvedTextEditorModel, ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { CommandsRegistry, ICommand, ICommandEvent, ICommandHandler, ICommandService } from 'vs/platform/commands/common/commands'; -import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; +import { IConfigurationChangeEvent, IConfigurationData, IConfigurationOverrides, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Configuration, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { ContextKeyExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IConfirmation, IConfirmationResult, IDialogOptions, IDialogService } from 'vs/platform/dialogs/common/dialogs'; @@ -37,8 +37,8 @@ import { IKeybindingItem, KeybindingsRegistry } from 'vs/platform/keybinding/com import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; import { ILabelService, ResourceLabelFormatter } from 'vs/platform/label/common/label'; -import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; -import { IProgressRunner, ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { INotification, INotificationHandle, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification } from 'vs/platform/notification/common/notification'; +import { IProgressRunner, IProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryInfo, ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspace, IWorkspaceContextService, IWorkspaceFolder, IWorkspaceFoldersChangeEvent, WorkbenchState, WorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; @@ -136,7 +136,7 @@ export class SimpleEditorModelResolverService implements ITextModelService { } } -export class SimpleLocalProgressService implements ILocalProgressService { +export class SimpleProgressService implements IProgressService { _serviceBrand: any; private static NULL_PROGRESS_RUNNER: IProgressRunner = { @@ -148,7 +148,7 @@ export class SimpleLocalProgressService implements ILocalProgressService { show(infinite: true, delay?: number): IProgressRunner; show(total: number, delay?: number): IProgressRunner; show(): IProgressRunner { - return SimpleLocalProgressService.NULL_PROGRESS_RUNNER; + return SimpleProgressService.NULL_PROGRESS_RUNNER; } showWhile(promise: Promise, delay?: number): Promise { @@ -220,10 +220,6 @@ export class SimpleNotificationService implements INotificationService { public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { return SimpleNotificationService.NO_OP; } - - public status(message: string | Error, options?: IStatusMessageOptions): IDisposable { - return Disposable.None; - } } export class StandaloneCommandService implements ICommandService { @@ -295,7 +291,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { throw new Error(`Invalid keybinding`); } - const toDispose = new DisposableStore(); + let toDispose: IDisposable[] = []; this._dynamicKeybindings.push({ keybinding: keybinding, @@ -305,7 +301,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { weight2: 0 }); - toDispose.add(toDisposable(() => { + toDispose.push(toDisposable(() => { for (let i = 0; i < this._dynamicKeybindings.length; i++) { let kb = this._dynamicKeybindings[i]; if (kb.command === commandId) { @@ -318,7 +314,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { let commandService = this._commandService; if (commandService instanceof StandaloneCommandService) { - toDispose.add(commandService.addCommand({ + toDispose.push(commandService.addCommand({ id: commandId, handler: handler })); @@ -327,7 +323,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { } this.updateResolver({ source: KeybindingSource.Default }); - return toDispose; + return combinedDisposable(toDispose); } private updateResolver(event: IKeybindingEvent): void { @@ -450,17 +446,7 @@ export class SimpleConfigurationService implements IConfigurationService { } public getConfigurationData(): IConfigurationData | null { - const emptyModel: IConfigurationModel = { - contents: {}, - keys: [], - overrides: [] - }; - return { - defaults: emptyModel, - user: emptyModel, - workspace: emptyModel, - folders: {} - }; + return null; } } diff --git a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts index 532eb6fdf7..9082b724ec 100644 --- a/src/vs/editor/standalone/browser/standaloneCodeEditor.ts +++ b/src/vs/editor/standalone/browser/standaloneCodeEditor.ts @@ -5,7 +5,7 @@ import * as browser from 'vs/base/browser/browser'; import * as aria from 'vs/base/browser/ui/aria/aria'; -import { Disposable, IDisposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ICodeEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -227,13 +227,13 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon }; - const toDispose = new DisposableStore(); + let toDispose: IDisposable[] = []; // Generate a unique id to allow the same descriptor.id across multiple editor instances const uniqueId = this.getId() + ':' + id; // Register the command - toDispose.add(CommandsRegistry.registerCommand(uniqueId, run)); + toDispose.push(CommandsRegistry.registerCommand(uniqueId, run)); // Register the context menu item if (contextMenuGroupId) { @@ -246,14 +246,16 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon group: contextMenuGroupId, order: contextMenuOrder }; - toDispose.add(MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem)); + toDispose.push(MenuRegistry.appendMenuItem(MenuId.EditorContext, menuItem)); } // Register the keybindings if (Array.isArray(keybindings)) { - for (const kb of keybindings) { - toDispose.add(this._standaloneKeybindingService.addDynamicKeybinding(uniqueId, kb, run, keybindingsWhen)); - } + toDispose = toDispose.concat( + keybindings.map((kb) => { + return this._standaloneKeybindingService.addDynamicKeybinding(uniqueId, kb, run, keybindingsWhen); + }) + ); } // Finally, register an internal editor action @@ -268,11 +270,11 @@ export class StandaloneCodeEditor extends CodeEditorWidget implements IStandalon // Store it under the original id, such that trigger with the original id will work this._actions[id] = internalAction; - toDispose.add(toDisposable(() => { + toDispose.push(toDisposable(() => { delete this._actions[id]; })); - return toDispose; + return combinedDisposable(toDispose); } } diff --git a/src/vs/editor/standalone/browser/standaloneLanguages.ts b/src/vs/editor/standalone/browser/standaloneLanguages.ts index 57af2eb87e..ee41d4a723 100644 --- a/src/vs/editor/standalone/browser/standaloneLanguages.ts +++ b/src/vs/editor/standalone/browser/standaloneLanguages.ts @@ -250,7 +250,7 @@ export interface IEncodedLineTokens { * - f = foreground ColorId (9 bits) * - b = background ColorId (9 bits) * - The color value for each colorId is defined in IStandaloneThemeData.customTokenColors: - * e.g. colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, + * e.g colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, * id = 1 is for the default foreground color, id = 2 for the default background. */ tokens: Uint32Array; @@ -427,7 +427,7 @@ export function registerCodeLensProvider(languageId: string, provider: modes.Cod */ export function registerCodeActionProvider(languageId: string, provider: CodeActionProvider): IDisposable { return modes.CodeActionProviderRegistry.register(languageId, { - provideCodeActions: (model: model.ITextModel, range: Range, context: modes.CodeActionContext, token: CancellationToken): modes.CodeActionList | Promise => { + provideCodeActions: (model: model.ITextModel, range: Range, context: modes.CodeActionContext, token: CancellationToken): (modes.Command | modes.CodeAction)[] | Promise<(modes.Command | modes.CodeAction)[]> => { let markers = StaticServices.markerService.get().read({ resource: model.uri }).filter(m => { return Range.areIntersectingOrTouching(m, range); }); @@ -510,7 +510,7 @@ export interface CodeActionProvider { /** * Provide commands for the given document and range. */ - provideCodeActions(model: model.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): modes.CodeActionList | Promise; + provideCodeActions(model: model.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): (modes.Command | modes.CodeAction)[] | Promise<(modes.Command | modes.CodeAction)[]>; } /** diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index db063e3512..5f9df5ce97 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -13,7 +13,7 @@ import { ModeServiceImpl } from 'vs/editor/common/services/modeServiceImpl'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { ITextResourceConfigurationService, ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; -import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleLocalProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleBulkEditService, SimpleConfigurationService, SimpleDialogService, SimpleNotificationService, SimpleProgressService, SimpleResourceConfigurationService, SimpleResourcePropertiesService, SimpleUriLabelService, SimpleWorkspaceContextService, StandaloneCommandService, StandaloneKeybindingService, StandaloneTelemetryService, SimpleLayoutService } from 'vs/editor/standalone/browser/simpleServices'; import { StandaloneCodeEditorServiceImpl } from 'vs/editor/standalone/browser/standaloneCodeServiceImpl'; import { StandaloneThemeServiceImpl } from 'vs/editor/standalone/browser/standaloneThemeServiceImpl'; import { IStandaloneThemeService } from 'vs/editor/standalone/common/standaloneThemeService'; @@ -36,7 +36,7 @@ import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { MarkerService } from 'vs/platform/markers/common/markerService'; import { IMarkerService } from 'vs/platform/markers/common/markers'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { IStorageService, InMemoryStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -150,7 +150,7 @@ export module StaticServices { export const codeEditorService = define(ICodeEditorService, (o) => new StandaloneCodeEditorServiceImpl(standaloneThemeService.get(o))); - export const localProgressService = define(ILocalProgressService, () => new SimpleLocalProgressService()); + export const progressService = define(IProgressService, () => new SimpleProgressService()); export const storageService = define(IStorageService, () => new InMemoryStorageService()); diff --git a/src/vs/editor/test/common/model/textModel.test.ts b/src/vs/editor/test/common/model/textModel.test.ts index e244a529da..ef24605e40 100644 --- a/src/vs/editor/test/common/model/textModel.test.ts +++ b/src/vs/editor/test/common/model/textModel.test.ts @@ -26,21 +26,17 @@ function testGuessIndentation(defaultInsertSpaces: boolean, defaultTabSize: numb assert.equal(r.tabSize, expectedTabSize, msg); } -function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined | [number], text: string[], msg?: string): void { +function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: number | undefined, text: string[], msg?: string): void { if (typeof expectedInsertSpaces === 'undefined') { // cannot guess insertSpaces if (typeof expectedTabSize === 'undefined') { // cannot guess tabSize testGuessIndentation(true, 13370, true, 13370, text, msg); testGuessIndentation(false, 13371, false, 13371, text, msg); - } else if (typeof expectedTabSize === 'number') { + } else { // can guess tabSize testGuessIndentation(true, 13370, true, expectedTabSize, text, msg); testGuessIndentation(false, 13371, false, expectedTabSize, text, msg); - } else { - // can only guess tabSize when insertSpaces is true - testGuessIndentation(true, 13370, true, expectedTabSize[0], text, msg); - testGuessIndentation(false, 13371, false, 13371, text, msg); } } else { // can guess insertSpaces @@ -48,19 +44,10 @@ function assertGuess(expectedInsertSpaces: boolean | undefined, expectedTabSize: // cannot guess tabSize testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg); testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg); - } else if (typeof expectedTabSize === 'number') { + } else { // can guess tabSize testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize, text, msg); testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize, text, msg); - } else { - // can only guess tabSize when insertSpaces is true - if (expectedInsertSpaces === true) { - testGuessIndentation(true, 13370, expectedInsertSpaces, expectedTabSize[0], text, msg); - testGuessIndentation(false, 13371, expectedInsertSpaces, expectedTabSize[0], text, msg); - } else { - testGuessIndentation(true, 13370, expectedInsertSpaces, 13370, text, msg); - testGuessIndentation(false, 13371, expectedInsertSpaces, 13371, text, msg); - } } } } @@ -232,7 +219,7 @@ suite('Editor Model - TextModel', () => { '\tx' ], '7xTAB'); - assertGuess(undefined, [2], [ + assertGuess(undefined, 2, [ '\tx', ' x', '\tx', @@ -252,7 +239,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x' ], '4x1, 4xTAB'); - assertGuess(false, undefined, [ + assertGuess(false, 2, [ '\tx', '\tx', ' x', @@ -263,7 +250,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '4x2, 5xTAB'); - assertGuess(false, undefined, [ + assertGuess(false, 2, [ '\tx', '\tx', 'x', @@ -274,7 +261,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '1x2, 5xTAB'); - assertGuess(false, undefined, [ + assertGuess(false, 4, [ '\tx', '\tx', 'x', @@ -285,7 +272,7 @@ suite('Editor Model - TextModel', () => { '\tx', ' x', ], '1x4, 5xTAB'); - assertGuess(false, undefined, [ + assertGuess(false, 2, [ '\tx', '\tx', 'x', @@ -537,7 +524,7 @@ suite('Editor Model - TextModel', () => { ' \t x', '\tx' ], 'mixed whitespace 1'); - assertGuess(false, undefined, [ + assertGuess(false, 4, [ '\tx', '\t x' ], 'mixed whitespace 2'); @@ -588,26 +575,6 @@ suite('Editor Model - TextModel', () => { ]); }); - test('issue #70832: Broken indentation detection', () => { - assertGuess(false, undefined, [ - 'x', - 'x', - 'x', - 'x', - ' x', - ' x', - ' x', - ' x', - ' x', - ' x', - ' x', - ' x', - ' x', - ' x', - 'x', - ]); - }); - test('validatePosition', () => { let m = TextModel.createFromString('line one\nline two'); diff --git a/src/vs/loader.js b/src/vs/loader.js index 6bbc54af69..3a57c5d59d 100644 --- a/src/vs/loader.js +++ b/src/vs/loader.js @@ -235,7 +235,6 @@ var AMDLoader; *--------------------------------------------------------------------------------------------*/ var AMDLoader; (function (AMDLoader) { - ; var ConfigurationOptionsUtil = (function () { function ConfigurationOptionsUtil() { } @@ -306,8 +305,22 @@ var AMDLoader; if (typeof options.nodeCachedData.writeDelay !== 'number' || options.nodeCachedData.writeDelay < 0) { options.nodeCachedData.writeDelay = 1000 * 7; } + if (typeof options.nodeCachedData.onData !== 'function') { + options.nodeCachedData.onData = function (err) { + if (err && err.errorCode === 'cachedDataRejected') { + console.warn('Rejected cached data from file: ' + err.path); + } + else if (err && err.errorCode) { + console.error('Problems handling cached data file: ' + err.path); + console.error(err.detail); + } + else if (err) { + console.error(err); + } + }; + } if (!options.nodeCachedData.path || typeof options.nodeCachedData.path !== 'string') { - options.onError('INVALID cached data configuration, \'path\' MUST be set'); + options.nodeCachedData.onData('INVALID cached data configuration, \'path\' MUST be set'); options.nodeCachedData = undefined; } } @@ -647,6 +660,7 @@ var AMDLoader; this._env = env; this._didInitialize = false; this._didPatchNodeRequire = false; + this._hasCreateCachedData = false; } NodeScriptLoader.prototype._init = function (nodeRequire) { if (this._didInitialize) { @@ -658,17 +672,14 @@ var AMDLoader; this._vm = nodeRequire('vm'); this._path = nodeRequire('path'); this._crypto = nodeRequire('crypto'); + // check for `createCachedData`-api + this._hasCreateCachedData = typeof (new this._vm.Script('').createCachedData) === 'function'; }; // patch require-function of nodejs such that we can manually create a script // from cached data. this is done by overriding the `Module._compile` function NodeScriptLoader.prototype._initNodeRequire = function (nodeRequire, moduleManager) { - // It is important to check for `nodeCachedData` first and then set `_didPatchNodeRequire`. - // That's because `nodeCachedData` is set _after_ calling this for the first time... var nodeCachedData = moduleManager.getConfig().getOptionsLiteral().nodeCachedData; - if (!nodeCachedData) { - return; - } - if (this._didPatchNodeRequire) { + if (!nodeCachedData || this._didPatchNodeRequire) { return; } this._didPatchNodeRequire = true; @@ -693,28 +704,25 @@ var AMDLoader; return require; } Module.prototype._compile = function (content, filename) { - // remove shebang and create wrapper function - var scriptSource = Module.wrap(content.replace(/^#!.*/, '')); - // create script - var recorder = moduleManager.getRecorder(); - var cachedDataPath = that._getCachedDataPath(nodeCachedData, filename); + // remove shebang + content = content.replace(/^#!.*/, ''); + // create wrapper function + var wrapper = Module.wrap(content); + var cachedDataPath = that._getCachedDataPath(nodeCachedData.seed, nodeCachedData.path, filename); var options = { filename: filename }; try { options.cachedData = that._fs.readFileSync(cachedDataPath); - recorder.record(60 /* CachedDataFound */, cachedDataPath); } - catch (_e) { - recorder.record(61 /* CachedDataMissed */, cachedDataPath); + catch (e) { + options.produceCachedData = !that._hasCreateCachedData; } - var script = new that._vm.Script(scriptSource, options); + var script = new that._vm.Script(wrapper, options); var compileWrapper = script.runInThisContext(options); - // run script var dirname = that._path.dirname(filename); var require = makeRequireFunction(this); var args = [this.exports, require, this, filename, dirname, process, _commonjsGlobal, Buffer]; var result = compileWrapper.apply(this.exports, args); - // cached data aftermath - setTimeout(function () { return that._handleCachedData(script, cachedDataPath, !options.cachedData, moduleManager); }, Math.ceil(moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay * Math.random())); + that._processCachedData(moduleManager, script, wrapper, cachedDataPath, !options.cachedData); return result; }; }; @@ -741,34 +749,57 @@ var AMDLoader; } else { scriptSrc = AMDLoader.Utilities.fileUriToFilePath(this._env.isWindows, scriptSrc); - var normalizedScriptSrc_1 = this._path.normalize(scriptSrc); - var vmScriptPathOrUri_1 = this._getElectronRendererScriptPathOrUri(normalizedScriptSrc_1); - var wantsCachedData_1 = Boolean(opts.nodeCachedData); - var cachedDataPath_1 = wantsCachedData_1 ? this._getCachedDataPath(opts.nodeCachedData, scriptSrc) : undefined; - this._readSourceAndCachedData(normalizedScriptSrc_1, cachedDataPath_1, recorder, function (err, data, cachedData) { + this._fs.readFile(scriptSrc, { encoding: 'utf8' }, function (err, data) { if (err) { errorback(err); return; } - var scriptSource; + var normalizedScriptSrc = _this._path.normalize(scriptSrc); + var vmScriptSrc = normalizedScriptSrc; + // Make the script src friendly towards electron + if (_this._env.isElectronRenderer) { + var driveLetterMatch = vmScriptSrc.match(/^([a-z])\:(.*)/i); + if (driveLetterMatch) { + // windows + vmScriptSrc = "file:///" + (driveLetterMatch[1].toUpperCase() + ':' + driveLetterMatch[2]).replace(/\\/g, '/'); + } + else { + // nix + vmScriptSrc = "file://" + vmScriptSrc; + } + } + var contents, prefix = '(function (require, define, __filename, __dirname) { ', suffix = '\n});'; if (data.charCodeAt(0) === NodeScriptLoader._BOM) { - scriptSource = NodeScriptLoader._PREFIX + data.substring(1) + NodeScriptLoader._SUFFIX; + contents = prefix + data.substring(1) + suffix; } else { - scriptSource = NodeScriptLoader._PREFIX + data + NodeScriptLoader._SUFFIX; + contents = prefix + data + suffix; + } + contents = nodeInstrumenter(contents, normalizedScriptSrc); + if (!opts.nodeCachedData) { + _this._loadAndEvalScript(moduleManager, scriptSrc, vmScriptSrc, contents, { filename: vmScriptSrc }, recorder, callback, errorback); + } + else { + var cachedDataPath_1 = _this._getCachedDataPath(opts.nodeCachedData.seed, opts.nodeCachedData.path, scriptSrc); + _this._fs.readFile(cachedDataPath_1, function (_err, cachedData) { + // create script options + var options = { + filename: vmScriptSrc, + produceCachedData: !_this._hasCreateCachedData && typeof cachedData === 'undefined', + cachedData: cachedData + }; + var script = _this._loadAndEvalScript(moduleManager, scriptSrc, vmScriptSrc, contents, options, recorder, callback, errorback); + _this._processCachedData(moduleManager, script, contents, cachedDataPath_1, !options.cachedData); + }); } - scriptSource = nodeInstrumenter(scriptSource, normalizedScriptSrc_1); - var scriptOpts = { filename: vmScriptPathOrUri_1, cachedData: cachedData }; - var script = _this._createAndEvalScript(moduleManager, scriptSource, scriptOpts, callback, errorback); - _this._handleCachedData(script, cachedDataPath_1, wantsCachedData_1 && !cachedData, moduleManager); }); } }; - NodeScriptLoader.prototype._createAndEvalScript = function (moduleManager, contents, options, callback, errorback) { - var recorder = moduleManager.getRecorder(); - recorder.record(31 /* NodeBeginEvaluatingScript */, options.filename); + NodeScriptLoader.prototype._loadAndEvalScript = function (moduleManager, scriptSrc, vmScriptSrc, contents, options, recorder, callback, errorback) { + // create script, run script + recorder.record(31 /* NodeBeginEvaluatingScript */, scriptSrc); var script = new this._vm.Script(contents, options); - var ret = script.runInThisContext(options); + var r = script.runInThisContext(options); var globalDefineFunc = moduleManager.getGlobalAMDDefineFunc(); var receivedDefineCall = false; var localDefineFunc = function () { @@ -776,112 +807,89 @@ var AMDLoader; return globalDefineFunc.apply(null, arguments); }; localDefineFunc.amd = globalDefineFunc.amd; - ret.call(AMDLoader.global, moduleManager.getGlobalAMDRequireFunc(), localDefineFunc, options.filename, this._path.dirname(options.filename)); - recorder.record(32 /* NodeEndEvaluatingScript */, options.filename); + r.call(AMDLoader.global, moduleManager.getGlobalAMDRequireFunc(), localDefineFunc, vmScriptSrc, this._path.dirname(scriptSrc)); + // signal done + recorder.record(32 /* NodeEndEvaluatingScript */, scriptSrc); if (receivedDefineCall) { callback(); } else { - errorback(new Error("Didn't receive define call in " + options.filename + "!")); + errorback(new Error("Didn't receive define call in " + scriptSrc + "!")); } return script; }; - NodeScriptLoader.prototype._getElectronRendererScriptPathOrUri = function (path) { - if (!this._env.isElectronRenderer) { - return path; - } - var driveLetterMatch = path.match(/^([a-z])\:(.*)/i); - if (driveLetterMatch) { - // windows - return "file:///" + (driveLetterMatch[1].toUpperCase() + ':' + driveLetterMatch[2]).replace(/\\/g, '/'); - } - else { - // nix - return "file://" + path; - } - }; - NodeScriptLoader.prototype._getCachedDataPath = function (config, filename) { - var hash = this._crypto.createHash('md5').update(filename, 'utf8').update(config.seed, 'utf8').digest('hex'); + NodeScriptLoader.prototype._getCachedDataPath = function (seed, basedir, filename) { + var hash = this._crypto.createHash('md5').update(filename, 'utf8').update(seed, 'utf8').digest('hex'); var basename = this._path.basename(filename).replace(/\.js$/, ''); - return this._path.join(config.path, basename + "-" + hash + ".code"); + return this._path.join(basedir, basename + "-" + hash + ".code"); }; - NodeScriptLoader.prototype._handleCachedData = function (script, cachedDataPath, createCachedData, moduleManager) { + NodeScriptLoader.prototype._processCachedData = function (moduleManager, script, contents, cachedDataPath, createCachedData) { var _this = this; if (script.cachedDataRejected) { - // cached data got rejected -> delete and re-create - this._fs.unlink(cachedDataPath, function (err) { - moduleManager.getRecorder().record(62 /* CachedDataRejected */, cachedDataPath); - _this._createAndWriteCachedData(script, cachedDataPath, moduleManager); - if (err) { - moduleManager.getConfig().onError(err); - } + // data rejected => delete cache file + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({ + errorCode: 'cachedDataRejected', + path: cachedDataPath }); - } - else if (createCachedData) { - // no cached data, but wanted - this._createAndWriteCachedData(script, cachedDataPath, moduleManager); - } - }; - NodeScriptLoader.prototype._createAndWriteCachedData = function (script, cachedDataPath, moduleManager) { - var _this = this; - var timeout = Math.ceil(moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay * (1 + Math.random())); - var lastSize = -1; - var iteration = 0; - var createLoop = function () { - setTimeout(function () { - var cachedData = script.createCachedData(); - if (cachedData.length === 0 || cachedData.length === lastSize || iteration >= 5) { - return; - } - lastSize = cachedData.length; - _this._fs.writeFile(cachedDataPath, cachedData, function (err) { + NodeScriptLoader._runSoon(function () { + return _this._fs.unlink(cachedDataPath, function (err) { if (err) { - moduleManager.getConfig().onError(err); + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({ + errorCode: 'unlink', + path: cachedDataPath, + detail: err + }); } - moduleManager.getRecorder().record(63 /* CachedDataCreated */, cachedDataPath); - createLoop(); }); - }, timeout * (Math.pow(4, iteration++))); - }; - // with some delay (`timeout`) create cached data - // and repeat that (with backoff delay) until the - // data seems to be not changing anymore - createLoop(); + }, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay / 2); + } + else if (script.cachedDataProduced) { + // data produced => tell outside world + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData(undefined, { + path: cachedDataPath + }); + // data produced => write cache file + NodeScriptLoader._runSoon(function () { + return _this._fs.writeFile(cachedDataPath, script.cachedData, function (err) { + if (err) { + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({ + errorCode: 'writeFile', + path: cachedDataPath, + detail: err + }); + } + }); + }, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay); + } + else if (this._hasCreateCachedData && createCachedData) { + // NEW world + // data produced => tell outside world + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData(undefined, { + path: cachedDataPath + }); + // soon'ish create and save cached data + NodeScriptLoader._runSoon(function () { + var data = script.createCachedData(contents); + _this._fs.writeFile(cachedDataPath, data, function (err) { + if (!err) { + return; + } + moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({ + errorCode: 'writeFile', + path: cachedDataPath, + detail: err + }); + }); + }, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay); + } }; - NodeScriptLoader.prototype._readSourceAndCachedData = function (sourcePath, cachedDataPath, recorder, callback) { - if (!cachedDataPath) { - // no cached data case - this._fs.readFile(sourcePath, { encoding: 'utf8' }, callback); - } - else { - // cached data case: read both files in parallel - var source_1; - var cachedData_1; - var steps_1 = 2; - var step_1 = function (err) { - if (err) { - callback(err); - } - else if (--steps_1 === 0) { - callback(undefined, source_1, cachedData_1); - } - }; - this._fs.readFile(sourcePath, { encoding: 'utf8' }, function (err, data) { - source_1 = data; - step_1(err); - }); - this._fs.readFile(cachedDataPath, function (err, data) { - cachedData_1 = data && data.length > 0 ? data : undefined; - step_1(); // ignored: cached data is optional - recorder.record(err ? 61 /* CachedDataMissed */ : 60 /* CachedDataFound */, cachedDataPath); - }); - } + NodeScriptLoader._runSoon = function (callback, minTimeout) { + var timeout = minTimeout + Math.ceil(Math.random() * minTimeout); + setTimeout(callback, timeout); }; return NodeScriptLoader; }()); NodeScriptLoader._BOM = 0xFEFF; - NodeScriptLoader._PREFIX = '(function (require, define, __filename, __dirname) { '; - NodeScriptLoader._SUFFIX = '\n});'; function createScriptLoader(env) { return new OnlyOnceScriptLoader(env); } diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 447f45fab0..59f31d4893 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -4275,7 +4275,7 @@ declare namespace monaco.languages { * - f = foreground ColorId (9 bits) * - b = background ColorId (9 bits) * - The color value for each colorId is defined in IStandaloneThemeData.customTokenColors: - * e.g. colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, + * e.g colorId = 1 is stored in IStandaloneThemeData.customTokenColors[1]. Color id = 0 means no color, * id = 1 is for the default foreground color, id = 2 for the default background. */ tokens: Uint32Array; @@ -4437,7 +4437,7 @@ declare namespace monaco.languages { /** * Provide commands for the given document and range. */ - provideCodeActions(model: editor.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): CodeActionList | Promise; + provideCodeActions(model: editor.ITextModel, range: Range, context: CodeActionContext, token: CancellationToken): (Command | CodeAction)[] | Promise<(Command | CodeAction)[]>; } /** @@ -4898,10 +4898,6 @@ declare namespace monaco.languages { isPreferred?: boolean; } - export interface CodeActionList extends IDisposable { - readonly actions: ReadonlyArray; - } - /** * Represents a parameter of a callable-signature. A parameter can * have a label and a doc-comment. @@ -5262,7 +5258,6 @@ declare namespace monaco.languages { export interface ILink { range: IRange; url?: Uri | string; - tooltip?: string; } export interface ILinksList { @@ -5351,6 +5346,7 @@ declare namespace monaco.languages { } export interface SelectionRange { + kind: string; range: IRange; } @@ -5457,21 +5453,16 @@ declare namespace monaco.languages { arguments?: any[]; } - export interface CodeLens { + export interface ICodeLensSymbol { range: IRange; id?: string; command?: Command; } - export interface CodeLensList { - lenses: CodeLens[]; - dispose(): void; - } - export interface CodeLensProvider { onDidChange?: IEvent; - provideCodeLenses(model: editor.ITextModel, token: CancellationToken): ProviderResult; - resolveCodeLens?(model: editor.ITextModel, codeLens: CodeLens, token: CancellationToken): ProviderResult; + provideCodeLenses(model: editor.ITextModel, token: CancellationToken): ProviderResult; + resolveCodeLens?(model: editor.ITextModel, codeLens: ICodeLensSymbol, token: CancellationToken): ProviderResult; } export interface ILanguageExtensionPoint { diff --git a/src/vs/platform/actions/common/menuService.ts b/src/vs/platform/actions/common/menuService.ts index 0e5b6686ed..ef9588a464 100644 --- a/src/vs/platform/actions/common/menuService.ts +++ b/src/vs/platform/actions/common/menuService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IMenu, IMenuActionOptions, IMenuItem, IMenuService, isIMenuItem, ISubmenuItem, MenuId, MenuItemAction, MenuRegistry, SubmenuItemAction } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr, IContextKeyService, IContextKeyChangeEvent } from 'vs/platform/contextkey/common/contextkey'; @@ -30,7 +30,7 @@ type MenuItemGroup = [string, Array]; class Menu implements IMenu { private readonly _onDidChange = new Emitter(); - private readonly _dispoables = new DisposableStore(); + private readonly _disposables: IDisposable[] = []; private _menuGroups: MenuItemGroup[]; private _contextKeys: Set; @@ -44,24 +44,19 @@ class Menu implements IMenu { // rebuild this menu whenever the menu registry reports an // event for this MenuId - this._dispoables.add(Event.debounce( + Event.debounce( Event.filter(MenuRegistry.onDidChangeMenu, menuId => menuId === this._id), () => { }, 50 - )(this._build, this)); + )(this._build, this, this._disposables); // when context keys change we need to check if the menu also // has changed - this._dispoables.add(Event.debounce( + Event.debounce( this._contextKeyService.onDidChangeContext, (last, event) => last || event.affectsSome(this._contextKeys), 50 - )(e => e && this._onDidChange.fire(undefined), this)); - } - - dispose(): void { - this._dispoables.dispose(); - this._onDidChange.dispose(); + )(e => e && this._onDidChange.fire(undefined), this, this._disposables); } private _build(): void { @@ -100,6 +95,11 @@ class Menu implements IMenu { this._onDidChange.fire(this); } + dispose() { + dispose(this._disposables); + this._onDidChange.dispose(); + } + get onDidChange(): Event { return this._onDidChange.event; } diff --git a/src/vs/platform/backup/electron-main/backupMainService.ts b/src/vs/platform/backup/electron-main/backupMainService.ts index c17cf27584..75bee0b950 100644 --- a/src/vs/platform/backup/electron-main/backupMainService.ts +++ b/src/vs/platform/backup/electron-main/backupMainService.ts @@ -244,7 +244,7 @@ export class BackupMainService implements IBackupMainService { return []; } - const seenIds: Set = new Set(); + const seenIds: { [id: string]: boolean } = Object.create(null); const result: IWorkspaceBackupInfo[] = []; // Validate Workspaces @@ -254,8 +254,8 @@ export class BackupMainService implements IBackupMainService { return []; // wrong format, skip all entries } - if (!seenIds.has(workspace.id)) { - seenIds.add(workspace.id); + if (!seenIds[workspace.id]) { + seenIds[workspace.id] = true; const backupPath = this.getBackupPath(workspace.id); const hasBackups = await this.hasBackups(backupPath); @@ -283,11 +283,11 @@ export class BackupMainService implements IBackupMainService { } const result: URI[] = []; - const seenIds: Set = new Set(); + const seen: { [id: string]: boolean } = Object.create(null); for (let folderURI of folderWorkspaces) { const key = getComparisonKey(folderURI); - if (!seenIds.has(key)) { - seenIds.add(key); + if (!seen[key]) { + seen[key] = true; const backupPath = this.getBackupPath(this.getFolderHash(folderURI)); const hasBackups = await this.hasBackups(backupPath); @@ -315,7 +315,7 @@ export class BackupMainService implements IBackupMainService { } const result: IEmptyWindowBackupInfo[] = []; - const seenIds: Set = new Set(); + const seen: { [id: string]: boolean } = Object.create(null); // Validate Empty Windows for (let backupInfo of emptyWorkspaces) { @@ -324,8 +324,8 @@ export class BackupMainService implements IBackupMainService { return []; } - if (!seenIds.has(backupFolder)) { - seenIds.add(backupFolder); + if (!seen[backupFolder]) { + seen[backupFolder] = true; const backupPath = this.getBackupPath(backupFolder); if (await this.hasBackups(backupPath)) { diff --git a/src/vs/platform/configuration/common/configurationRegistry.ts b/src/vs/platform/configuration/common/configurationRegistry.ts index 2c93e7b17c..c8cf252e69 100644 --- a/src/vs/platform/configuration/common/configurationRegistry.ts +++ b/src/vs/platform/configuration/common/configurationRegistry.ts @@ -131,13 +131,11 @@ export interface IDefaultConfigurationExtension { defaults: { [key: string]: {} }; } -type SettingProperties = { [key: string]: any }; - -export const allSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; -export const applicationSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; -export const machineSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; -export const windowSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; -export const resourceSettings: { properties: SettingProperties, patternProperties: SettingProperties } = { properties: {}, patternProperties: {} }; +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: {} }; export const editorConfigurationSchemaId = 'vscode://schemas/settings/editor'; const contributionRegistry = Registry.as(JSONExtensions.JSONContribution); diff --git a/src/vs/platform/configuration/node/configuration.ts b/src/vs/platform/configuration/node/configuration.ts new file mode 100644 index 0000000000..53d7d1da6d --- /dev/null +++ b/src/vs/platform/configuration/node/configuration.ts @@ -0,0 +1,56 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Disposable } from 'vs/base/common/lifecycle'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { ConfigurationModelParser, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; +import { ConfigWatcher } from 'vs/base/node/config'; +import { Event, Emitter } from 'vs/base/common/event'; + +export class NodeBasedUserConfiguration extends Disposable { + + private userConfigModelWatcher: ConfigWatcher; + private initializePromise: Promise; + + private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); + readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; + + constructor(private settingsPath: string) { + super(); + } + + initialize(): Promise { + if (!this.initializePromise) { + this.initializePromise = new Promise((c, e) => { + this.userConfigModelWatcher = new ConfigWatcher(this.settingsPath, { + changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.settingsPath), parse: (content: string, parseErrors: any[]) => { + const userConfigModelParser = new ConfigurationModelParser(this.settingsPath); + userConfigModelParser.parseContent(content); + parseErrors = [...userConfigModelParser.errors]; + return userConfigModelParser; + }, initCallback: () => c(undefined) + }); + this._register(this.userConfigModelWatcher); + + // Listeners + this._register(this.userConfigModelWatcher.onDidUpdateConfiguration(() => this._onDidChangeConfiguration.fire(this.userConfigModelWatcher.getConfig().configurationModel))); + }); + } + return this.initializePromise.then(() => this.userConfigModelWatcher.getConfig().configurationModel); + } + + initializeSync(): ConfigurationModel { + this.initialize(); + return this.userConfigModelWatcher.getConfig().configurationModel; + } + + reload(): Promise { + return this.initialize().then(() => new Promise(c => this.userConfigModelWatcher.reload(userConfigModelParser => c(userConfigModelParser.configurationModel)))); + } + + getConfigurationModel(): ConfigurationModel { + return this.userConfigModelWatcher.getConfig().configurationModel; + } +} \ No newline at end of file diff --git a/src/vs/platform/configuration/node/configurationService.ts b/src/vs/platform/configuration/node/configurationService.ts index 01cef6c8c3..eb55d0e780 100644 --- a/src/vs/platform/configuration/node/configurationService.ts +++ b/src/vs/platform/configuration/node/configurationService.ts @@ -7,49 +7,40 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { IConfigurationService, IConfigurationChangeEvent, IConfigurationOverrides, ConfigurationTarget, compare, isConfigurationOverrides, IConfigurationData } from 'vs/platform/configuration/common/configuration'; -import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels'; +import { DefaultConfigurationModel, Configuration, ConfigurationChangeEvent, ConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { ConfigWatcher } from 'vs/base/node/config'; -import { onUnexpectedError } from 'vs/base/common/errors'; +import { NodeBasedUserConfiguration } from 'vs/platform/configuration/node/configuration'; export class ConfigurationService extends Disposable implements IConfigurationService, IDisposable { _serviceBrand: any; - private configuration: Configuration; - private userConfigModelWatcher: ConfigWatcher | undefined; + private _configuration: Configuration; + private userConfiguration: NodeBasedUserConfiguration; private readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; constructor( - private readonly configurationPath: string + configurationPath: string ) { super(); - this.configuration = new Configuration(new DefaultConfigurationModel(), new ConfigurationModel()); + + this.userConfiguration = this._register(new NodeBasedUserConfiguration(configurationPath)); + + // Initialize + const defaults = new DefaultConfigurationModel(); + const user = this.userConfiguration.initializeSync(); + this._configuration = new Configuration(defaults, user); + + // Listeners + this._register(this.userConfiguration.onDidChangeConfiguration(userConfigurationModel => this.onDidChangeUserConfiguration(userConfigurationModel))); this._register(Registry.as(Extensions.Configuration).onDidUpdateConfiguration(configurationProperties => this.onDidDefaultConfigurationChange(configurationProperties))); } - initialize(): Promise { - if (this.userConfigModelWatcher) { - this.userConfigModelWatcher.dispose(); - } - - return new Promise((c, e) => { - this.userConfigModelWatcher = this._register(new ConfigWatcher(this.configurationPath, { - changeBufferDelay: 300, onError: error => onUnexpectedError(error), defaultConfig: new ConfigurationModelParser(this.configurationPath), parse: (content: string, parseErrors: any[]) => { - const userConfigModelParser = new ConfigurationModelParser(this.configurationPath); - userConfigModelParser.parseContent(content); - parseErrors = [...userConfigModelParser.errors]; - return userConfigModelParser; - }, initCallback: () => { - this.configuration = new Configuration(new DefaultConfigurationModel(), this.userConfigModelWatcher!.getConfig().configurationModel); - this._register(this.userConfigModelWatcher!.onDidUpdateConfiguration(() => this.onDidChangeUserConfiguration(this.userConfigModelWatcher!.getConfig().configurationModel))); - c(); - } - })); - }); + get configuration(): Configuration { + return this._configuration; } getConfigurationData(): IConfigurationData { @@ -94,26 +85,21 @@ export class ConfigurationService extends Disposable implements IConfigurationSe } reloadConfiguration(folder?: IWorkspaceFolder): Promise { - if (this.userConfigModelWatcher) { - return new Promise(c => this.userConfigModelWatcher!.reload(userConfigModelParser => { - this.onDidChangeUserConfiguration(userConfigModelParser.configurationModel); - c(); - })); - } - return this.initialize(); + return folder ? Promise.resolve(undefined) : + this.userConfiguration.reload().then(userConfigurationModel => this.onDidChangeUserConfiguration(userConfigurationModel)); } private onDidChangeUserConfiguration(userConfigurationModel: ConfigurationModel): void { - const { added, updated, removed } = compare(this.configuration.localUserConfiguration, userConfigurationModel); + const { added, updated, removed } = compare(this._configuration.localUserConfiguration, userConfigurationModel); const changedKeys = [...added, ...updated, ...removed]; if (changedKeys.length) { - this.configuration.updateLocalUserConfiguration(userConfigurationModel); + this._configuration.updateLocalUserConfiguration(userConfigurationModel); this.trigger(changedKeys, ConfigurationTarget.USER); } } private onDidDefaultConfigurationChange(keys: string[]): void { - this.configuration.updateDefaultConfiguration(new DefaultConfigurationModel()); + this._configuration.updateDefaultConfiguration(new DefaultConfigurationModel()); this.trigger(keys, ConfigurationTarget.DEFAULT); } @@ -124,9 +110,9 @@ export class ConfigurationService extends Disposable implements IConfigurationSe private getTargetConfiguration(target: ConfigurationTarget): any { switch (target) { case ConfigurationTarget.DEFAULT: - return this.configuration.defaults.contents; + return this._configuration.defaults.contents; case ConfigurationTarget.USER: - return this.configuration.localUserConfiguration.contents; + return this._configuration.localUserConfiguration.contents; } return {}; } diff --git a/src/vs/platform/configuration/test/common/configuration.test.ts b/src/vs/platform/configuration/test/common/configuration.test.ts index 4ff1a7973f..1e3662c3dd 100644 --- a/src/vs/platform/configuration/test/common/configuration.test.ts +++ b/src/vs/platform/configuration/test/common/configuration.test.ts @@ -32,7 +32,7 @@ suite('Configuration', () => { assert.deepEqual(target, { 'a': { 'b': 2 } }); }); - test('removeFromValueTree: remove a single segmented key', () => { + test('removeFromValueTree: remove a single segemented key', () => { let target = { 'a': 1 }; removeFromValueTree(target, 'a'); @@ -40,7 +40,7 @@ suite('Configuration', () => { assert.deepEqual(target, {}); }); - test('removeFromValueTree: remove a single segmented key when its value is undefined', () => { + test('removeFromValueTree: remove a single segemented key when its value is undefined', () => { let target = { 'a': undefined }; removeFromValueTree(target, 'a'); @@ -48,7 +48,7 @@ suite('Configuration', () => { assert.deepEqual(target, {}); }); - test('removeFromValueTree: remove a multi segmented key when its value is undefined', () => { + test('removeFromValueTree: remove a multi segemented key when its value is undefined', () => { let target = { 'a': { 'b': 1 } }; removeFromValueTree(target, 'a.b'); @@ -56,7 +56,7 @@ suite('Configuration', () => { assert.deepEqual(target, {}); }); - test('removeFromValueTree: remove a multi segmented key when its value is array', () => { + test('removeFromValueTree: remove a multi segemented key when its value is array', () => { let target = { 'a': { 'b': [1] } }; removeFromValueTree(target, 'a.b'); @@ -64,7 +64,7 @@ suite('Configuration', () => { assert.deepEqual(target, {}); }); - test('removeFromValueTree: remove a multi segmented key first segment value is array', () => { + test('removeFromValueTree: remove a multi segemented key first segment value is array', () => { let target = { 'a': [1] }; removeFromValueTree(target, 'a.0'); @@ -80,7 +80,7 @@ suite('Configuration', () => { assert.deepEqual(target, {}); }); - test('removeFromValueTree: remove a multi segmented key when the first node has more values', () => { + test('removeFromValueTree: remove a multi segemented key when the first node has more values', () => { let target = { 'a': { 'b': { 'c': 1 }, 'd': 1 } }; removeFromValueTree(target, 'a.b.c'); @@ -88,7 +88,7 @@ suite('Configuration', () => { assert.deepEqual(target, { 'a': { 'd': 1 } }); }); - test('removeFromValueTree: remove a multi segmented key when in between node has more values', () => { + test('removeFromValueTree: remove a multi segemented key when in between node has more values', () => { let target = { 'a': { 'b': { 'c': { 'd': 1 }, 'd': 1 } } }; removeFromValueTree(target, 'a.b.c.d'); @@ -96,7 +96,7 @@ suite('Configuration', () => { assert.deepEqual(target, { 'a': { 'b': { 'd': 1 } } }); }); - test('removeFromValueTree: remove a multi segmented key when the last but one node has more values', () => { + test('removeFromValueTree: remove a multi segemented key when the last but one node has more values', () => { let target = { 'a': { 'b': { 'c': 1, 'd': 1 } } }; removeFromValueTree(target, 'a.b.c'); diff --git a/src/vs/platform/configuration/test/common/configurationModels.test.ts b/src/vs/platform/configuration/test/common/configurationModels.test.ts index 4d8d25f090..adb8538d5c 100644 --- a/src/vs/platform/configuration/test/common/configurationModels.test.ts +++ b/src/vs/platform/configuration/test/common/configurationModels.test.ts @@ -82,7 +82,7 @@ suite('ConfigurationModel', () => { assert.deepEqual(testObject.keys, ['a.b']); }); - test('removeValue: remove a single segmented key', () => { + test('removeValue: remove a single segemented key', () => { let testObject = new ConfigurationModel({ 'a': 1 }, ['a']); testObject.removeValue('a'); @@ -91,7 +91,7 @@ suite('ConfigurationModel', () => { assert.deepEqual(testObject.keys, []); }); - test('removeValue: remove a multi segmented key', () => { + test('removeValue: remove a multi segemented key', () => { let testObject = new ConfigurationModel({ 'a': { 'b': 1 } }, ['a.b']); testObject.removeValue('a.b'); diff --git a/src/vs/platform/configuration/test/node/configurationService.test.ts b/src/vs/platform/configuration/test/node/configurationService.test.ts index fc86fe7cb2..90fad2fafc 100644 --- a/src/vs/platform/configuration/test/node/configurationService.test.ts +++ b/src/vs/platform/configuration/test/node/configurationService.test.ts @@ -21,7 +21,6 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(res.testFile, '{ "foo": "bar" }'); const service = new ConfigurationService(res.testFile); - await service.initialize(); const config = service.getValue<{ foo: string; }>(); @@ -39,7 +38,6 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(res.testFile, '{ "testworkbench.editor.tabs": true }'); const service = new ConfigurationService(res.testFile); - await service.initialize(); const config = service.getValue<{ testworkbench: { editor: { @@ -62,7 +60,6 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(res.testFile, ',,,,'); const service = new ConfigurationService(res.testFile); - await service.initialize(); const config = service.getValue<{ foo: string; }>(); @@ -72,14 +69,13 @@ suite('ConfigurationService - Node', () => { return res.cleanUp(); }); - test('missing file does not explode', async () => { + test('missing file does not explode', () => { const id = uuid.generateUuid(); const parentDir = path.join(os.tmpdir(), 'vsctests', id); const newDir = path.join(parentDir, 'config', id); const testFile = path.join(newDir, 'config.json'); const service = new ConfigurationService(testFile); - await service.initialize(); const config = service.getValue<{ foo: string }>(); assert.ok(config); @@ -91,7 +87,6 @@ suite('ConfigurationService - Node', () => { const res = await testFile('config', 'config.json'); const service = new ConfigurationService(res.testFile); - await service.initialize(); return new Promise((c, e) => { service.onDidChangeConfiguration(() => { assert.equal(service.getValue('foo'), 'bar'); @@ -109,7 +104,6 @@ suite('ConfigurationService - Node', () => { fs.writeFileSync(res.testFile, '{ "foo": "bar" }'); const service = new ConfigurationService(res.testFile); - await service.initialize(); let config = service.getValue<{ foo: string; }>(); @@ -136,7 +130,7 @@ suite('ConfigurationService - Node', () => { return res.cleanUp(); }); - test('model defaults', async () => { + test('model defaults', () => { interface ITestSetting { configuration: { service: { @@ -158,7 +152,6 @@ suite('ConfigurationService - Node', () => { }); let serviceWithoutFile = new ConfigurationService('__testFile'); - await serviceWithoutFile.initialize(); let setting = serviceWithoutFile.getValue(); assert.ok(setting); @@ -201,8 +194,6 @@ suite('ConfigurationService - Node', () => { const r = await testFile('config', 'config.json'); const service = new ConfigurationService(r.testFile); - service.initialize(); - let res = service.inspect('something.missing'); assert.strictEqual(res.value, undefined); assert.strictEqual(res.default, undefined); @@ -239,8 +230,6 @@ suite('ConfigurationService - Node', () => { const r = await testFile('config', 'config.json'); const service = new ConfigurationService(r.testFile); - service.initialize(); - let res = service.inspect('lookup.service.testNullSetting'); assert.strictEqual(res.default, null); assert.strictEqual(res.value, null); diff --git a/src/vs/platform/contextview/browser/contextMenuHandler.ts b/src/vs/platform/contextview/browser/contextMenuHandler.ts index 234433710e..1d0f5c8bb6 100644 --- a/src/vs/platform/contextview/browser/contextMenuHandler.ts +++ b/src/vs/platform/contextview/browser/contextMenuHandler.ts @@ -5,7 +5,7 @@ import 'vs/css!./contextMenuHandler'; -import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { ActionRunner, IRunEvent } from 'vs/base/common/actions'; import { Menu } from 'vs/base/browser/ui/menu/menu'; import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; @@ -104,7 +104,7 @@ export class ContextMenuHandler { this.contextViewService.hideContextView(true); }, null, menuDisposables); - return combinedDisposable(...menuDisposables, menu); + return combinedDisposable([...menuDisposables, menu]); }, focus: () => { diff --git a/src/vs/platform/credentials/common/credentials.ts b/src/vs/platform/credentials/common/credentials.ts deleted file mode 100644 index f538dd6486..0000000000 --- a/src/vs/platform/credentials/common/credentials.ts +++ /dev/null @@ -1,16 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -export const ICredentialsService = createDecorator('ICredentialsService'); - -export interface ICredentialsService { - _serviceBrand: any; - getPassword(service: string, account: string): Promise; - setPassword(service: string, account: string, password: string): Promise; - deletePassword(service: string, account: string): Promise; - findPassword(service: string): Promise; -} diff --git a/src/vs/platform/credentials/node/credentialsService.ts b/src/vs/platform/credentials/node/credentialsService.ts deleted file mode 100644 index c86aece4d2..0000000000 --- a/src/vs/platform/credentials/node/credentialsService.ts +++ /dev/null @@ -1,41 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import { IdleValue } from 'vs/base/common/async'; - -type KeytarModule = { - getPassword(service: string, account: string): Promise; - setPassword(service: string, account: string, password: string): Promise; - deletePassword(service: string, account: string): Promise; - findPassword(service: string): Promise; -}; - -export class KeytarCredentialsService implements ICredentialsService { - - _serviceBrand: any; - - private readonly _keytar = new IdleValue>(() => import('keytar')); - - async getPassword(service: string, account: string): Promise { - const keytar = await this._keytar.getValue(); - return keytar.getPassword(service, account); - } - - async setPassword(service: string, account: string, password: string): Promise { - const keytar = await this._keytar.getValue(); - return keytar.setPassword(service, account, password); - } - - async deletePassword(service: string, account: string): Promise { - const keytar = await this._keytar.getValue(); - return keytar.deletePassword(service, account); - } - - async findPassword(service: string): Promise { - const keytar = await this._keytar.getValue(); - return keytar.findPassword(service); - } -} diff --git a/src/vs/platform/dialogs/common/dialogs.ts b/src/vs/platform/dialogs/common/dialogs.ts index 29e20c79cd..590c0cbdbe 100644 --- a/src/vs/platform/dialogs/common/dialogs.ts +++ b/src/vs/platform/dialogs/common/dialogs.ts @@ -36,7 +36,7 @@ export interface IConfirmationResult { /** * This will only be defined if the confirmation was created - * with the checkbox option defined. + * with the checkox option defined. */ checkboxChecked?: boolean; } diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index f5772d4296..7f7a939264 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -10,7 +10,7 @@ import { IMainProcessService } from 'vs/platform/ipc/electron-browser/mainProces import { getTopLeftOffset, getClientArea } from 'vs/base/browser/dom'; import * as electron from 'electron'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { Terminal } from 'xterm'; +import { Terminal } from 'vscode-xterm'; import { timeout } from 'vs/base/common/async'; import { coalesce } from 'vs/base/common/arrays'; diff --git a/src/vs/platform/driver/electron-main/driver.ts b/src/vs/platform/driver/electron-main/driver.ts index 90e93eae7e..fab602c592 100644 --- a/src/vs/platform/driver/electron-main/driver.ts +++ b/src/vs/platform/driver/electron-main/driver.ts @@ -210,5 +210,5 @@ export async function serve( const channel = new DriverChannel(driver); server.registerChannel('driver', channel); - return combinedDisposable(server, windowServer); + return combinedDisposable([server, windowServer]); } diff --git a/src/vs/platform/editor/common/editor.ts b/src/vs/platform/editor/common/editor.ts index f3785d10a6..3b8d1d395f 100644 --- a/src/vs/platform/editor/common/editor.ts +++ b/src/vs/platform/editor/common/editor.ts @@ -95,17 +95,15 @@ export interface IEditorOptions { readonly forceReload?: boolean; /** - * Will reveal the editor if it is already opened and visible in any of the opened editor groups. - * - * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly + * Will reveal the editor if it is already opened and visible in any of the opened editor groups. Note + * that this option is just a hint that might be ignored if the user wants to open an editor explicitly * to the side of another one or into a specific editor group. */ readonly revealIfVisible?: boolean; /** - * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups. - * - * Note that this option is just a hint that might be ignored if the user wants to open an editor explicitly + * Will reveal the editor if it is already opened (even when not visible) in any of the opened editor groups. Note + * that this option is just a hint that might be ignored if the user wants to open an editor explicitly * to the side of another one or into a specific editor group. */ readonly revealIfOpened?: boolean; diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index 61b323aafb..0ad08e381a 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -27,6 +27,7 @@ export interface ParsedArgs { 'prof-startup'?: string; 'prof-startup-prefix'?: string; 'prof-append-timers'?: string; + 'prof-modules'?: string; verbose?: boolean; trace?: boolean; 'trace-category-filter'?: string; @@ -68,7 +69,6 @@ export interface ParsedArgs { 'driver'?: string; 'driver-verbose'?: boolean; remote?: string; - 'disable-user-env-probe'?: boolean; // {{SQL CARBON EDIT}} aad?: boolean; database?: string; @@ -105,7 +105,7 @@ export interface IEnvironmentService { appNameLong: string; appQuality?: string; appSettingsHome: string; - settingsResource: URI; + appSettingsPath: string; appKeybindingsPath: string; machineSettingsHome: string; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index aca016a422..e7b612ea04 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -8,7 +8,7 @@ import * as os from 'os'; import { localize } from 'vs/nls'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { join } from 'vs/base/common/path'; -import { writeFileSync } from 'vs/base/node/pfs'; +import { writeFileSync } from 'fs'; /** * This code is also used by standalone cli's. Avoid adding any other dependencies. @@ -54,6 +54,7 @@ export const options: Option[] = [ { id: 'verbose', type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") }, { id: 'log', type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") }, { id: 'status', type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") }, + { id: 'prof-modules', type: 'boolean', alias: 'p', cat: 't', description: localize('prof-modules', "Capture performance markers while loading JS modules and print them with 'F1 > Developer: Startup Performance") }, { id: 'prof-startup', type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") }, { id: 'disable-extensions', type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") }, { id: 'disable-extension', type: 'string', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") }, diff --git a/src/vs/platform/environment/node/environmentService.ts b/src/vs/platform/environment/node/environmentService.ts index 50888922d5..977cb51bbd 100644 --- a/src/vs/platform/environment/node/environmentService.ts +++ b/src/vs/platform/environment/node/environmentService.ts @@ -21,9 +21,7 @@ import { URI } from 'vs/base/common/uri'; const xdgRuntimeDir = process.env['XDG_RUNTIME_DIR']; function getNixIPCHandle(userDataPath: string, type: string): string { - const vscodePortable = process.env['VSCODE_PORTABLE']; - - if (xdgRuntimeDir && !vscodePortable) { + if (xdgRuntimeDir) { const scope = crypto.createHash('md5').update(userDataPath).digest('hex').substr(0, 8); return path.join(xdgRuntimeDir, `vscode-${scope}-${pkg.version}-${type}.sock`); } @@ -95,7 +93,6 @@ export class EnvironmentService implements IEnvironmentService { @memoize get userDataPath(): string { const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'user-data'); } @@ -111,7 +108,7 @@ export class EnvironmentService implements IEnvironmentService { get appSettingsHome(): string { return path.join(this.userDataPath, 'User'); } @memoize - get settingsResource(): URI { return URI.file(path.join(this.appSettingsHome, 'settings.json')); } + get appSettingsPath(): string { return path.join(this.appSettingsHome, 'settings.json'); } @memoize get machineSettingsHome(): string { return path.join(this.userDataPath, 'Machine'); } @@ -173,7 +170,6 @@ export class EnvironmentService implements IEnvironmentService { } const vscodePortable = process.env['VSCODE_PORTABLE']; - if (vscodePortable) { return path.join(vscodePortable, 'extensions'); } @@ -293,7 +289,6 @@ export function parseDebugPort(debugArg: string | undefined, debugBrkArg: string const portStr = debugBrkArg || debugArg; const port = Number(portStr) || (!isBuild ? defaultBuildPort : null); const brk = port ? Boolean(!!debugBrkArg) : false; - return { port, break: brk, debugId }; } @@ -308,9 +303,9 @@ function parsePathArg(arg: string | undefined, process: NodeJS.Process): string if (path.normalize(arg) === resolved) { return resolved; + } else { + return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); } - - return path.resolve(process.env['VSCODE_CWD'] || process.cwd(), arg); } export function parseUserDataDir(args: ParsedArgs, process: NodeJS.Process): string { diff --git a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts index 59077e4336..b21c8851fb 100644 --- a/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts +++ b/src/vs/platform/extensionManagement/common/extensionManagementUtil.ts @@ -5,7 +5,6 @@ import { ILocalExtension, IGalleryExtension, IExtensionIdentifier, IReportedExtension } from 'vs/platform/extensionManagement/common/extensionManagement'; import { compareIgnoreCase } from 'vs/base/common/strings'; -import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifier): boolean { if (a.uuid && b.uuid) { @@ -17,24 +16,6 @@ export function areSameExtensions(a: IExtensionIdentifier, b: IExtensionIdentifi return compareIgnoreCase(a.id, b.id) === 0; } -export class ExtensionIdentifierWithVersion { - constructor( - readonly identifier: IExtensionIdentifier, - readonly version: string - ) { } - - key(): string { - return `${this.identifier.id}-${this.version}`; - } - - equals(o: any): boolean { - if (!(o instanceof ExtensionIdentifierWithVersion)) { - return false; - } - return areSameExtensions(this.identifier, o.identifier) && this.version === o.version; - } -} - export function adoptToGalleryExtensionId(id: string): string { return id.toLocaleLowerCase(); } @@ -108,7 +89,7 @@ export function getGalleryExtensionTelemetryData(extension: IGalleryExtension): }; } -export const BetterMergeId = new ExtensionIdentifier('pprice.better-merge'); +export const BetterMergeId = 'pprice.better-merge'; export function getMaliciousExtensionsSet(report: IReportedExtension[]): Set { const result = new Set(); diff --git a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts index 0bdaba0e6c..0050543941 100644 --- a/src/vs/platform/extensionManagement/node/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/node/extensionGalleryService.ts @@ -828,7 +828,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { /* __GDPR__ "galleryService:requestError" : { "url" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "cdn": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "cdn": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, "message": { "classification": "CallstackOrException", "purpose": "FeatureInsight" } } */ diff --git a/src/vs/platform/extensionManagement/node/extensionManagementService.ts b/src/vs/platform/extensionManagement/node/extensionManagementService.ts index 86167face6..62f9c97fc7 100644 --- a/src/vs/platform/extensionManagement/node/extensionManagementService.ts +++ b/src/vs/platform/extensionManagement/node/extensionManagementService.ts @@ -21,7 +21,7 @@ import { INSTALL_ERROR_MALICIOUS, INSTALL_ERROR_INCOMPATIBLE } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { areSameExtensions, getGalleryExtensionId, groupByExtension, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { areSameExtensions, getGalleryExtensionId, groupByExtension, getMaliciousExtensionsSet, getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localizeManifest } from '../common/extensionNls'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { Limiter, createCancelablePromise, CancelablePromise, Queue } from 'vs/base/common/async'; @@ -44,7 +44,7 @@ import { Schemas } from 'vs/base/common/network'; import { CancellationToken } from 'vs/base/common/cancellation'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; -import { IExtensionManifest, ExtensionType } from 'vs/platform/extensions/common/extensions'; +import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion } from 'vs/platform/extensions/common/extensions'; // {{SQL CARBON EDIT} import product from 'vs/platform/product/node/product'; @@ -117,16 +117,16 @@ export class ExtensionManagementService extends Disposable implements IExtension private readonly manifestCache: ExtensionsManifestCache; private readonly extensionLifecycle: ExtensionsLifecycle; - private readonly _onInstallExtension = this._register(new Emitter()); + private readonly _onInstallExtension = new Emitter(); readonly onInstallExtension: Event = this._onInstallExtension.event; - private readonly _onDidInstallExtension = this._register(new Emitter()); + private readonly _onDidInstallExtension = new Emitter(); readonly onDidInstallExtension: Event = this._onDidInstallExtension.event; - private readonly _onUninstallExtension = this._register(new Emitter()); + private readonly _onUninstallExtension = new Emitter(); readonly onUninstallExtension: Event = this._onUninstallExtension.event; - private _onDidUninstallExtension = this._register(new Emitter()); + private _onDidUninstallExtension = new Emitter(); onDidUninstallExtension: Event = this._onDidUninstallExtension.event; constructor( @@ -287,6 +287,9 @@ export class ExtensionManagementService extends Disposable implements IExtension async installFromGallery(extension: IGalleryExtension): Promise { const startTime = new Date().getTime(); + this.logService.info('Installing extension:', extension.identifier.id); + this._onInstallExtension.fire({ identifier: extension.identifier, gallery: extension }); + const onDidInstallExtensionSuccess = (extension: IGalleryExtension, operation: InstallOperation, local: ILocalExtension) => { this.logService.info(`Extensions installed successfully:`, extension.identifier.id); this._onDidInstallExtension.fire({ identifier: extension.identifier, gallery: extension, local, operation }); @@ -314,9 +317,6 @@ export class ExtensionManagementService extends Disposable implements IExtension let cancellablePromise = this.installingExtensions.get(key); if (!cancellablePromise) { - this.logService.info('Installing extension:', extension.identifier.id); - this._onInstallExtension.fire({ identifier: extension.identifier, gallery: extension }); - let operation: InstallOperation = InstallOperation.Install; let cancellationToken: CancellationToken, successCallback: (a?: any) => void, errorCallback: (e?: any) => any | null; cancellablePromise = createCancelablePromise(token => { cancellationToken = token; return new Promise((c, e) => { successCallback = c; errorCallback = e; }); }); @@ -367,7 +367,7 @@ export class ExtensionManagementService extends Disposable implements IExtension const compatibleExtension = await this.galleryService.getCompatibleExtension(extension); if (!compatibleExtension) { - return Promise.reject(new ExtensionManagementError(nls.localize('notFoundCompatibleDependency', "Unable to install '{0}' extension because it is not compatible with the current version of VS Code (version {1}).", extension.identifier.id, pkg.version), INSTALL_ERROR_INCOMPATIBLE)); + return Promise.reject(new ExtensionManagementError(nls.localize('notFoundCompatibleDependency', "Unable to install because, the extension '{0}' compatible with current version '{1}' of VS Code is not found.", extension.identifier.id, pkg.version), INSTALL_ERROR_INCOMPATIBLE)); } return compatibleExtension; @@ -500,12 +500,12 @@ export class ExtensionManagementService extends Disposable implements IExtension e => Promise.reject(new ExtensionManagementError(this.joinErrors(e).message, INSTALL_ERROR_DELETING))); } - private rename(identifier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise { + private rename(identfier: IExtensionIdentifier, extractPath: string, renamePath: string, retryUntil: number): Promise { return pfs.rename(extractPath, renamePath) .then(undefined, error => { if (isWindows && error && error.code === 'EPERM' && Date.now() < retryUntil) { - this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identifier.id); - return this.rename(identifier, extractPath, renamePath, retryUntil); + this.logService.info(`Failed renaming ${extractPath} to ${renamePath} with 'EPERM' error. Trying again...`, identfier.id); + return this.rename(identfier, extractPath, renamePath, retryUntil); } return Promise.reject(new ExtensionManagementError(error.message || nls.localize('renameError', "Unknown error while renaming {0} to {1}", extractPath, renamePath), error.code || INSTALL_ERROR_RENAMING)); }); @@ -743,7 +743,7 @@ export class ExtensionManagementService extends Disposable implements IExtension this.logService.trace('Started scanning system extensions'); const systemExtensionsPromise = this.scanExtensions(this.systemExtensionsPath, ExtensionType.System) .then(result => { - this.logService.trace('Scanned system extensions:', result.length); + this.logService.info('Scanned system extensions:', result.length); return result; }); if (this.environmentService.isBuilt) { @@ -756,7 +756,7 @@ export class ExtensionManagementService extends Disposable implements IExtension if (devSystemExtensionsList.length) { return this.scanExtensions(this.devSystemExtensionsPath, ExtensionType.System) .then(result => { - this.logService.trace('Scanned dev system extensions:', result.length); + this.logService.info('Scanned dev system extensions:', result.length); return result.filter(r => devSystemExtensionsList.some(id => areSameExtensions(r.identifier, { id }))); }); } else { @@ -776,7 +776,7 @@ export class ExtensionManagementService extends Disposable implements IExtension const byExtension: ILocalExtension[][] = groupByExtension(extensions, e => e.identifier); extensions = byExtension.map(p => p.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version))[0]); } - this.logService.trace('Scanned user extensions:', extensions.length); + this.logService.info('Scanned user extensions:', extensions.length); return extensions; }); } @@ -806,29 +806,19 @@ export class ExtensionManagementService extends Disposable implements IExtension .then(undefined, () => null); } - async removeDeprecatedExtensions(): Promise { - await this.removeUninstalledExtensions(); - await this.removeOutdatedExtensions(); + removeDeprecatedExtensions(): Promise { + return this.removeUninstalledExtensions() + .then(() => this.removeOutdatedExtensions()); } - private async removeUninstalledExtensions(): Promise { - const uninstalled = await this.getUninstalledExtensions(); - const extensions = await this.scanExtensions(this.extensionsPath, ExtensionType.User); // All user extensions - const installed: Set = new Set(); - for (const e of extensions) { - if (!uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]) { - installed.add(e.identifier.id.toLowerCase()); - } - } - const byExtension: ILocalExtension[][] = groupByExtension(extensions, e => e.identifier); - await Promise.all(byExtension.map(async e => { - const latest = e.sort((a, b) => semver.rcompare(a.manifest.version, b.manifest.version))[0]; - if (!installed.has(latest.identifier.id.toLowerCase())) { - await this.extensionLifecycle.postUninstall(latest); - } - })); - const toRemove: ILocalExtension[] = extensions.filter(e => uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]); - await Promise.all(toRemove.map(e => this.removeUninstalledExtension(e))); + private removeUninstalledExtensions(): Promise { + return this.getUninstalledExtensions() + .then(uninstalled => this.scanExtensions(this.extensionsPath, ExtensionType.User) // All user extensions + .then(extensions => { + const toRemove: ILocalExtension[] = extensions.filter(e => uninstalled[new ExtensionIdentifierWithVersion(e.identifier, e.manifest.version).key()]); + return Promise.all(toRemove.map(e => this.extensionLifecycle.postUninstall(e).then(() => this.removeUninstalledExtension(e)))); + }) + ).then(() => undefined); } private removeOutdatedExtensions(): Promise { @@ -855,8 +845,8 @@ export class ExtensionManagementService extends Disposable implements IExtension return pfs.rimraf(extension.location.fsPath).then(() => this.logService.info('Deleted from disk', extension.identifier.id, extension.location.fsPath)); } - private isUninstalled(identifier: ExtensionIdentifierWithVersion): Promise { - return this.filterUninstalled(identifier).then(uninstalled => uninstalled.length === 1); + private isUninstalled(identfier: ExtensionIdentifierWithVersion): Promise { + return this.filterUninstalled(identfier).then(uninstalled => uninstalled.length === 1); } private filterUninstalled(...identifiers: ExtensionIdentifierWithVersion[]): Promise { diff --git a/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts b/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts index e160016700..7804936c43 100644 --- a/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts +++ b/src/vs/platform/extensionManagement/node/extensionsManifestCache.ts @@ -16,11 +16,11 @@ export class ExtensionsManifestCache extends Disposable { constructor( private readonly environmentService: IEnvironmentService, - extensionsManagementService: IExtensionManagementService + extensionsManagementServuce: IExtensionManagementService ) { super(); - this._register(extensionsManagementService.onDidInstallExtension(e => this.onDidInstallExtension(e))); - this._register(extensionsManagementService.onDidUninstallExtension(e => this.onDidUnInstallExtension(e))); + this._register(extensionsManagementServuce.onDidInstallExtension(e => this.onDidInstallExtension(e))); + this._register(extensionsManagementServuce.onDidUninstallExtension(e => this.onDidUnInstallExtension(e))); } private onDidInstallExtension(e: DidInstallExtensionEvent): void { diff --git a/src/vs/platform/extensions/common/extensions.ts b/src/vs/platform/extensions/common/extensions.ts index b3eb2e9d81..a9f503039c 100644 --- a/src/vs/platform/extensions/common/extensions.ts +++ b/src/vs/platform/extensions/common/extensions.ts @@ -3,6 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import * as strings from 'vs/base/common/strings'; import { ILocalization } from 'vs/platform/localizations/common/localizations'; import { URI } from 'vs/base/common/uri'; @@ -108,6 +109,24 @@ export interface IExtensionContributions { export type ExtensionKind = 'ui' | 'workspace'; +export class ExtensionIdentifierWithVersion { + constructor( + readonly identifier: IExtensionIdentifier, + readonly version: string + ) { } + + key(): string { + return `${this.identifier.id}-${this.version}`; + } + + equals(o: any): boolean { + if (!(o instanceof ExtensionIdentifierWithVersion)) { + return false; + } + return areSameExtensions(this.identifier, o.identifier) && this.version === o.version; + } +} + export function isIExtensionIdentifier(thing: any): thing is IExtensionIdentifier { return thing && typeof thing === 'object' diff --git a/src/vs/platform/files/common/files.ts b/src/vs/platform/files/common/files.ts index 49fc2e784a..051f19e146 100644 --- a/src/vs/platform/files/common/files.ts +++ b/src/vs/platform/files/common/files.ts @@ -517,7 +517,7 @@ interface IBaseStat { resource: URI; /** - * The name which is the last segment + * The name which is the last segement * of the {{path}}. */ name: string; @@ -531,7 +531,7 @@ interface IBaseStat { size?: number; /** - * The last modification date represented + * The last modifictaion date represented * as millis from unix epoch. * * The value may or may not be resolved as diff --git a/src/vs/platform/history/electron-main/historyMainService.ts b/src/vs/platform/history/electron-main/historyMainService.ts index ae198bf70c..7788d772d1 100644 --- a/src/vs/platform/history/electron-main/historyMainService.ts +++ b/src/vs/platform/history/electron-main/historyMainService.ts @@ -22,8 +22,6 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { getSimpleWorkspaceLabel } from 'vs/platform/label/common/label'; import { toStoreData, restoreRecentlyOpened, RecentlyOpenedStorageData } from 'vs/platform/history/electron-main/historyStorage'; import { exists } from 'vs/base/node/pfs'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { ILifecycleService, LifecycleMainPhase } from 'vs/platform/lifecycle/electron-main/lifecycleMain'; export class HistoryMainService implements IHistoryMainService { @@ -39,10 +37,10 @@ export class HistoryMainService implements IHistoryMainService { private static readonly recentlyOpenedStorageKey = 'openedPathsList'; - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; private _onRecentlyOpenedChange = new Emitter(); - readonly onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; + onRecentlyOpenedChange: CommonEvent = this._onRecentlyOpenedChange.event; private macOSRecentDocumentsUpdater: ThrottledDelayer; @@ -50,21 +48,9 @@ export class HistoryMainService implements IHistoryMainService { @IStateService private readonly stateService: IStateService, @ILogService private readonly logService: ILogService, @IWorkspacesMainService private readonly workspacesMainService: IWorkspacesMainService, - @IEnvironmentService private readonly environmentService: IEnvironmentService, - @ILifecycleService lifecycleService: ILifecycleService + @IEnvironmentService private readonly environmentService: IEnvironmentService ) { this.macOSRecentDocumentsUpdater = new ThrottledDelayer(800); - - lifecycleService.when(LifecycleMainPhase.AfterWindowOpen).then(() => this.handleWindowsJumpList()); - } - - private handleWindowsJumpList(): void { - if (!isWindows) { - return; // only on windows - } - - this.updateWindowsJumpList(); - this.onRecentlyOpenedChange(() => this.updateWindowsJumpList()); } addRecentlyOpened(newlyAdded: IRecent[]): void { diff --git a/src/vs/platform/keybinding/common/abstractKeybindingService.ts b/src/vs/platform/keybinding/common/abstractKeybindingService.ts index 95e7a9af99..e56e69cd7d 100644 --- a/src/vs/platform/keybinding/common/abstractKeybindingService.ts +++ b/src/vs/platform/keybinding/common/abstractKeybindingService.ts @@ -15,6 +15,7 @@ import { IKeybindingEvent, IKeybindingService, IKeyboardEvent } from 'vs/platfor import { IResolveResult, KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; interface CurrentChord { @@ -25,32 +26,45 @@ interface CurrentChord { export abstract class AbstractKeybindingService extends Disposable implements IKeybindingService { public _serviceBrand: any; - protected readonly _onDidUpdateKeybindings: Emitter = this._register(new Emitter()); - get onDidUpdateKeybindings(): Event { - return this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype - } - private _currentChord: CurrentChord | null; private _currentChordChecker: IntervalTimer; private _currentChordStatusMessage: IDisposable | null; + protected _onDidUpdateKeybindings: Emitter; + + private _contextKeyService: IContextKeyService; + private _statusService: IStatusbarService | undefined; + private _notificationService: INotificationService; + protected _commandService: ICommandService; + protected _telemetryService: ITelemetryService; constructor( - private _contextKeyService: IContextKeyService, - protected _commandService: ICommandService, - protected _telemetryService: ITelemetryService, - private _notificationService: INotificationService, + contextKeyService: IContextKeyService, + commandService: ICommandService, + telemetryService: ITelemetryService, + notificationService: INotificationService, + statusService?: IStatusbarService ) { super(); + this._contextKeyService = contextKeyService; + this._commandService = commandService; + this._telemetryService = telemetryService; + this._statusService = statusService; + this._notificationService = notificationService; this._currentChord = null; this._currentChordChecker = new IntervalTimer(); this._currentChordStatusMessage = null; + this._onDidUpdateKeybindings = this._register(new Emitter()); } public dispose(): void { super.dispose(); } + get onDidUpdateKeybindings(): Event { + return this._onDidUpdateKeybindings ? this._onDidUpdateKeybindings.event : Event.None; // Sinon stubbing walks properties on prototype + } + protected abstract _getResolver(): KeybindingResolver; protected abstract _documentHasFocus(): boolean; public abstract resolveKeybinding(keybinding: Keybinding): ResolvedKeybinding[]; @@ -114,7 +128,9 @@ export abstract class AbstractKeybindingService extends Disposable implements IK keypress: firstPart, label: keypressLabel }; - this._currentChordStatusMessage = this._notificationService.status(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel)); + if (this._statusService) { + this._currentChordStatusMessage = this._statusService.setStatusMessage(nls.localize('first.chord', "({0}) was pressed. Waiting for second key of chord...", keypressLabel)); + } const chordEnterTime = Date.now(); this._currentChordChecker.cancelAndSet(() => { @@ -176,9 +192,9 @@ export abstract class AbstractKeybindingService extends Disposable implements IK return shouldPreventDefault; } - if (this._currentChord) { + if (this._statusService && this._currentChord) { if (!resolveResult || !resolveResult.commandId) { - this._notificationService.status(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", this._currentChord.label, keypressLabel), { hideAfter: 10 * 1000 /* 10s */ }); + this._statusService.setStatusMessage(nls.localize('missing.chord', "The key combination ({0}, {1}) is not a command.", this._currentChord.label, keypressLabel), 10 * 1000 /* 10s */); shouldPreventDefault = true; } } diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index ab4bdcadfd..d477d1679c 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; import { KeyChord, KeyCode, KeyMod, Keybinding, ResolvedKeybinding, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { OS } from 'vs/base/common/platform'; import Severity from 'vs/base/common/severity'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -13,9 +14,9 @@ import { IKeyboardEvent } from 'vs/platform/keybinding/common/keybinding'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; -import { INotification, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationService, IPromptChoice, IPromptOptions, NoOpNotification } from 'vs/platform/notification/common/notification'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { NullTelemetryService } from 'vs/platform/telemetry/common/telemetryUtils'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; function createContext(ctx: any) { return { @@ -34,9 +35,10 @@ suite('AbstractKeybindingService', () => { resolver: KeybindingResolver, contextKeyService: IContextKeyService, commandService: ICommandService, - notificationService: INotificationService + notificationService: INotificationService, + statusService?: IStatusbarService ) { - super(contextKeyService, commandService, NullTelemetryService, notificationService); + super(contextKeyService, commandService, NullTelemetryService, notificationService, statusService); this._resolver = resolver; } @@ -127,7 +129,7 @@ suite('AbstractKeybindingService', () => { }; let notificationService: INotificationService = { - _serviceBrand: {} as ServiceIdentifier, + _serviceBrand: undefined, notify: (notification: INotification) => { showMessageCalls.push({ sev: notification.severity, message: notification.message }); return new NoOpNotification(); @@ -146,8 +148,13 @@ suite('AbstractKeybindingService', () => { }, prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions) { throw new Error('not implemented'); - }, - status(message: string, options?: IStatusMessageOptions) { + } + }; + + let statusbarService: IStatusbarService = { + _serviceBrand: undefined, + addEntry: undefined!, + setStatusMessage: (message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable => { statusMessageCalls!.push(message); return { dispose: () => { @@ -159,7 +166,7 @@ suite('AbstractKeybindingService', () => { let resolver = new KeybindingResolver(items, []); - return new TestKeybindingService(resolver, contextKeyService, commandService, notificationService); + return new TestKeybindingService(resolver, contextKeyService, commandService, notificationService, statusbarService); }; }); diff --git a/src/vs/platform/launch/electron-main/launchService.ts b/src/vs/platform/launch/electron-main/launchService.ts index 1f01c4528b..45470961db 100644 --- a/src/vs/platform/launch/electron-main/launchService.ts +++ b/src/vs/platform/launch/electron-main/launchService.ts @@ -8,7 +8,7 @@ import { ILogService } from 'vs/platform/log/common/log'; import { IURLService } from 'vs/platform/url/common/url'; import { IProcessEnvironment, isMacintosh } from 'vs/base/common/platform'; import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { OpenContext, IWindowSettings } from 'vs/platform/windows/common/windows'; import { IWindowsMainService, ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { whenDeleted } from 'vs/base/node/pfs'; @@ -107,7 +107,7 @@ export class LaunchChannel implements IServerChannel { export class LaunchChannelClient implements ILaunchService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; constructor(private channel: IChannel) { } @@ -134,7 +134,7 @@ export class LaunchChannelClient implements ILaunchService { export class LaunchService implements ILaunchService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; constructor( @ILogService private readonly logService: ILogService, diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index 22e4d2ca0b..ac1c8b6c99 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -29,7 +29,7 @@ export interface BeforeShutdownEvent { /** * The reason why the application will be shutting down. */ - readonly reason: ShutdownReason; + reason: ShutdownReason; } /** @@ -51,7 +51,7 @@ export interface WillShutdownEvent { /** * The reason why the application is shutting down. */ - readonly reason: ShutdownReason; + reason: ShutdownReason; } export const enum ShutdownReason { diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts index 1a0a1e9089..3c53a936cb 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts @@ -7,12 +7,11 @@ import { ipcMain as ipc, app } from 'electron'; import { ILogService } from 'vs/platform/log/common/log'; import { IStateService } from 'vs/platform/state/common/state'; import { Event, Emitter } from 'vs/base/common/event'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { ICodeWindow } from 'vs/platform/windows/electron-main/windows'; import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; import { isMacintosh, isWindows } from 'vs/base/common/platform'; import { Disposable } from 'vs/base/common/lifecycle'; -import { Barrier } from 'vs/base/common/async'; export const ILifecycleService = createDecorator('lifecycleService'); @@ -39,48 +38,42 @@ export interface ShutdownEvent { } export interface ILifecycleService { - - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; /** * Will be true if the program was restarted (e.g. due to explicit request or update). */ - readonly wasRestarted: boolean; + wasRestarted: boolean; /** * Will be true if the program was requested to quit. */ - readonly quitRequested: boolean; - - /** - * A flag indicating in what phase of the lifecycle we currently are. - */ - phase: LifecycleMainPhase; + quitRequested: boolean; /** * An event that fires when the application is about to shutdown before any window is closed. * The shutdown can still be prevented by any window that vetos this event. */ - readonly onBeforeShutdown: Event; + onBeforeShutdown: Event; /** * An event that fires after the onBeforeShutdown event has been fired and after no window has * vetoed the shutdown sequence. At this point listeners are ensured that the application will * quit without veto. */ - readonly onWillShutdown: Event; + onWillShutdown: Event; /** * An event that fires before a window closes. This event is fired after any veto has been dealt * with so that listeners know for sure that the window will close without veto. */ - readonly onBeforeWindowClose: Event; + onBeforeWindowClose: Event; /** * An event that fires before a window is about to unload. Listeners can veto this event to prevent * the window from unloading. */ - readonly onBeforeWindowUnload: Event; + onBeforeWindowUnload: Event; /** * Unload a window for the provided reason. All lifecycle event handlers are triggered. @@ -101,32 +94,6 @@ export interface ILifecycleService { * Forcefully shutdown the application. No livecycle event handlers are triggered. */ kill(code?: number): void; - - /** - * Returns a promise that resolves when a certain lifecycle phase - * has started. - */ - when(phase: LifecycleMainPhase): Promise; -} - -export const enum LifecycleMainPhase { - - /** - * The first phase signals that we are about to startup. - */ - Starting = 1, - - /** - * Services are ready and first window is about to open. - */ - Ready = 2, - - /** - * This phase signals a point in time after the window has opened - * and is typically the best place to do work that is not required - * for the window to open. - */ - AfterWindowOpen = 3 } export class LifecycleService extends Disposable implements ILifecycleService { @@ -135,7 +102,7 @@ export class LifecycleService extends Disposable implements ILifecycleService { private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted - private windowToCloseRequest: Set = new Set(); + private windowToCloseRequest: { [windowId: string]: boolean } = Object.create(null); private oneTimeListenerTokenGenerator = 0; private windowCounter = 0; @@ -162,11 +129,6 @@ export class LifecycleService extends Disposable implements ILifecycleService { private readonly _onBeforeWindowUnload = this._register(new Emitter()); readonly onBeforeWindowUnload: Event = this._onBeforeWindowUnload.event; - private _phase: LifecycleMainPhase = LifecycleMainPhase.Starting; - get phase(): LifecycleMainPhase { return this._phase; } - - private phaseWhen = new Map(); - constructor( @ILogService private readonly logService: ILogService, @IStateService private readonly stateService: IStateService @@ -174,7 +136,6 @@ export class LifecycleService extends Disposable implements ILifecycleService { super(); this.handleRestarted(); - this.when(LifecycleMainPhase.Ready).then(() => this.registerListeners()); } private handleRestarted(): void { @@ -185,6 +146,10 @@ export class LifecycleService extends Disposable implements ILifecycleService { } } + ready(): void { + this.registerListeners(); + } + private registerListeners(): void { // before-quit: an event that is fired if application quit was @@ -273,40 +238,6 @@ export class LifecycleService extends Disposable implements ILifecycleService { return this.pendingWillShutdownPromise; } - set phase(value: LifecycleMainPhase) { - if (value < this.phase) { - throw new Error('Lifecycle cannot go backwards'); - } - - if (this._phase === value) { - return; - } - - this.logService.trace(`lifecycle (main): phase changed (value: ${value})`); - - this._phase = value; - - const barrier = this.phaseWhen.get(this._phase); - if (barrier) { - barrier.open(); - this.phaseWhen.delete(this._phase); - } - } - - async when(phase: LifecycleMainPhase): Promise { - if (phase <= this._phase) { - return; - } - - let barrier = this.phaseWhen.get(phase); - if (!barrier) { - barrier = new Barrier(); - this.phaseWhen.set(phase, barrier); - } - - await barrier.wait(); - } - registerWindow(window: ICodeWindow): void { // track window count @@ -317,8 +248,8 @@ export class LifecycleService extends Disposable implements ILifecycleService { // The window already acknowledged to be closed const windowId = window.id; - if (this.windowToCloseRequest.has(windowId)) { - this.windowToCloseRequest.delete(windowId); + if (this.windowToCloseRequest[windowId]) { + delete this.windowToCloseRequest[windowId]; return; } @@ -329,11 +260,11 @@ export class LifecycleService extends Disposable implements ILifecycleService { e.preventDefault(); this.unload(window, UnloadReason.CLOSE).then(veto => { if (veto) { - this.windowToCloseRequest.delete(windowId); + delete this.windowToCloseRequest[windowId]; return; } - this.windowToCloseRequest.add(windowId); + this.windowToCloseRequest[windowId] = true; // Fire onBeforeWindowClose before actually closing this.logService.trace(`Lifecycle#onBeforeWindowClose.fire() - window ID ${windowId}`); @@ -459,6 +390,10 @@ export class LifecycleService extends Disposable implements ILifecycleService { }); } + /** + * A promise that completes to indicate if the quit request has been veto'd + * by the user or not. + */ quit(fromUpdate?: boolean): Promise { if (this.pendingQuitPromise) { return this.pendingQuitPromise; diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index 83cf9898bc..a1aea75a55 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -8,7 +8,7 @@ import { IListMouseEvent, IListTouchEvent, IListRenderer, IListVirtualDelegate } import { IPagedRenderer, PagedList } from 'vs/base/browser/ui/list/listPaging'; import { DefaultStyleController, IListOptions, IMultipleSelectionController, IOpenController, isSelectionRangeChangeEvent, isSelectionSingleChangeEvent, List } from 'vs/base/browser/ui/list/listWidget'; import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable, dispose, IDisposable, toDisposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { combinedDisposable, Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { isUndefinedOrNull } from 'vs/base/common/types'; import { ITree, ITreeConfiguration, ITreeOptions } from 'vs/base/parts/tree/browser/tree'; @@ -78,7 +78,7 @@ export class ListService implements IListService { this._lastFocusedWidget = widget; } - return combinedDisposable( + const result = combinedDisposable([ widget.onDidFocus(() => this._lastFocusedWidget = widget), toDisposable(() => this.lists.splice(this.lists.indexOf(registeredList), 1)), widget.onDidDispose(() => { @@ -87,7 +87,9 @@ export class ListService implements IListService { this._lastFocusedWidget = undefined; } }) - ); + ]); + + return result; } } @@ -198,18 +200,18 @@ class WorkbenchOpenController extends Disposable implements IOpenController { } function toWorkbenchListOptions(options: IListOptions, configurationService: IConfigurationService, keybindingService: IKeybindingService): [IListOptions, IDisposable] { - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const result = { ...options }; if (options.multipleSelectionSupport !== false && !options.multipleSelectionController) { const multipleSelectionController = new MultipleSelectionController(configurationService); result.multipleSelectionController = multipleSelectionController; - disposables.add(multipleSelectionController); + disposables.push(multipleSelectionController); } const openController = new WorkbenchOpenController(configurationService, options.openController); result.openController = openController; - disposables.add(openController); + disposables.push(openController); if (options.keyboardNavigationLabelProvider) { const tlp = options.keyboardNavigationLabelProvider; @@ -220,7 +222,7 @@ function toWorkbenchListOptions(options: IListOptions, configurationServic }; } - return [result, disposables]; + return [result, combinedDisposable(disposables)]; } let sharedListStyleSheet: HTMLStyleElement; @@ -281,7 +283,7 @@ export class WorkbenchList extends List { this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService); - this.disposables.push( + this.disposables.push(combinedDisposable([ this.contextKeyService, (listService as ListService).register(this), attachListStyler(this, themeService), @@ -299,7 +301,7 @@ export class WorkbenchList extends List { this.listHasSelectionOrFocus.set(selection.length > 0 || focus.length > 0); }) - ); + ])); this.registerListeners(); } @@ -322,7 +324,7 @@ export class WorkbenchPagedList extends PagedList { readonly contextKeyService: IContextKeyService; private readonly configurationService: IConfigurationService; - private readonly disposables: DisposableStore; + private disposables: IDisposable[]; private _useAltAsMultipleSelectionModifier: boolean; @@ -349,8 +351,7 @@ export class WorkbenchPagedList extends PagedList { } ); - this.disposables = new DisposableStore(); - this.disposables.add(workbenchListOptionsDisposable); + this.disposables = [workbenchListOptionsDisposable]; this.contextKeyService = createScopedContextKeyService(contextKeyService, this); this.configurationService = configurationService; @@ -360,15 +361,17 @@ export class WorkbenchPagedList extends PagedList { this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(configurationService); - this.disposables.add(this.contextKeyService); - this.disposables.add((listService as ListService).register(this)); - this.disposables.add(attachListStyler(this, themeService)); + this.disposables.push(combinedDisposable([ + this.contextKeyService, + (listService as ListService).register(this), + attachListStyler(this, themeService) + ])); this.registerListeners(); } private registerListeners(): void { - this.disposables.add(this.configurationService.onDidChangeConfiguration(e => { + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(multiSelectModifierSettingKey)) { this._useAltAsMultipleSelectionModifier = useAltAsMultipleSelectionModifier(this.configurationService); } @@ -382,7 +385,7 @@ export class WorkbenchPagedList extends PagedList { dispose(): void { super.dispose(); - this.disposables.dispose(); + this.disposables = dispose(this.disposables); } } @@ -530,7 +533,7 @@ function massageControllerOptions(options: IControllerOptions): IControllerOptio */ export class WorkbenchTreeController extends DefaultController { - protected readonly disposables = new DisposableStore(); + protected disposables: IDisposable[] = []; constructor( options: IControllerOptions, @@ -546,7 +549,7 @@ export class WorkbenchTreeController extends DefaultController { } private registerListeners(): void { - this.disposables.add(this.configurationService.onDidChangeConfiguration(e => { + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(openModeSettingKey)) { this.setOpenMode(this.getOpenModeSetting()); } @@ -558,7 +561,7 @@ export class WorkbenchTreeController extends DefaultController { } dispose(): void { - this.disposables.dispose(); + this.disposables = dispose(this.disposables); } } diff --git a/src/vs/platform/log/common/log.ts b/src/vs/platform/log/common/log.ts index 25a67c3b41..c50401d9f9 100644 --- a/src/vs/platform/log/common/log.ts +++ b/src/vs/platform/log/common/log.ts @@ -186,7 +186,7 @@ export class ConsoleLogService extends AbstractLogService implements ILogService export class MultiplexLogService extends AbstractLogService implements ILogService { _serviceBrand: any; - constructor(private readonly logServices: ReadonlyArray) { + constructor(private logServices: ILogService[]) { super(); if (logServices.length) { this.setLevel(logServices[0].getLevel()); diff --git a/src/vs/platform/log/node/spdlogService.ts b/src/vs/platform/log/node/spdlogService.ts index ca02c8c3ac..b4326bab5e 100644 --- a/src/vs/platform/log/node/spdlogService.ts +++ b/src/vs/platform/log/node/spdlogService.ts @@ -4,20 +4,24 @@ *--------------------------------------------------------------------------------------------*/ import * as path from 'vs/base/common/path'; -import { ILogService, LogLevel, AbstractLogService } from 'vs/platform/log/common/log'; +import { ILogService, LogLevel, NullLogService, AbstractLogService } from 'vs/platform/log/common/log'; import * as spdlog from 'spdlog'; +import { BufferLogService } from 'vs/platform/log/common/bufferLog'; -async function createSpdLogLogger(processName: string, logsFolder: string): Promise { +export async function createSpdLogService(processName: string, logLevel: LogLevel, logsFolder: string): Promise { // Do not crash if spdlog cannot be loaded try { - const _spdlog = await import('spdlog'); + const _spdlog: typeof spdlog = require.__$__nodeRequire('spdlog'); _spdlog.setAsyncMode(8192, 500); const logfilePath = path.join(logsFolder, `${processName}.log`); - return _spdlog.createRotatingLoggerAsync(processName, logfilePath, 1024 * 1024 * 5, 6); + const logger = await _spdlog.createRotatingLoggerAsync(processName, logfilePath, 1024 * 1024 * 5, 6); + logger.setLevel(0); + + return new SpdLogService(logger, logLevel); } catch (e) { console.error(e); } - return null; + return new NullLogService(); } export function createRotatingLogger(name: string, filename: string, filesize: number, filecount: number): spdlog.RotatingLogger { @@ -25,88 +29,45 @@ export function createRotatingLogger(name: string, filename: string, filesize: n return _spdlog.createRotatingLogger(name, filename, filesize, filecount); } -interface ILog { - level: LogLevel; - message: string; +export function createBufferSpdLogService(processName: string, logLevel: LogLevel, logsFolder: string): ILogService { + const bufferLogService = new BufferLogService(); + createSpdLogService(processName, logLevel, logsFolder).then(logger => bufferLogService.logger = logger); + return bufferLogService; } -function log(logger: spdlog.RotatingLogger, level: LogLevel, message: string): void { - switch (level) { - case LogLevel.Trace: return logger.trace(message); - case LogLevel.Debug: return logger.debug(message); - case LogLevel.Info: return logger.info(message); - case LogLevel.Warning: return logger.warn(message); - case LogLevel.Error: return logger.error(message); - case LogLevel.Critical: return logger.critical(message); - default: throw new Error('Invalid log level'); - } -} - -export class SpdLogService extends AbstractLogService implements ILogService { +class SpdLogService extends AbstractLogService implements ILogService { _serviceBrand: any; - private buffer: ILog[] = []; - private _loggerCreationPromise: Promise | undefined = undefined; - private _logger: spdlog.RotatingLogger | undefined; - - constructor(private readonly name: string, private readonly logsFolder: string, level: LogLevel) { + constructor( + private readonly logger: spdlog.RotatingLogger, + level: LogLevel = LogLevel.Error + ) { super(); this.setLevel(level); - this._createSpdLogLogger(); - this._register(this.onDidChangeLogLevel(level => { - if (this._logger) { - this._logger.setLevel(level); - } - })); - } - - private _createSpdLogLogger(): Promise { - if (!this._loggerCreationPromise) { - this._loggerCreationPromise = createSpdLogLogger(this.name, this.logsFolder) - .then(logger => { - if (logger) { - this._logger = logger; - this._logger.setLevel(this.getLevel()); - for (const { level, message } of this.buffer) { - log(this._logger, level, message); - } - this.buffer = []; - } - }); - } - return this._loggerCreationPromise; - } - - private _log(level: LogLevel, message: string): void { - if (this._logger) { - log(this._logger, level, message); - } else if (this.getLevel() <= level) { - this.buffer.push({ level, message }); - } } trace(): void { if (this.getLevel() <= LogLevel.Trace) { - this._log(LogLevel.Trace, this.format(arguments)); + this.logger.trace(this.format(arguments)); } } debug(): void { if (this.getLevel() <= LogLevel.Debug) { - this._log(LogLevel.Debug, this.format(arguments)); + this.logger.debug(this.format(arguments)); } } info(): void { if (this.getLevel() <= LogLevel.Info) { - this._log(LogLevel.Info, this.format(arguments)); + this.logger.info(this.format(arguments)); } } warn(): void { if (this.getLevel() <= LogLevel.Warning) { - this._log(LogLevel.Warning, this.format(arguments)); + this.logger.warn(this.format(arguments)); } } @@ -117,33 +78,21 @@ export class SpdLogService extends AbstractLogService implements ILogService { if (arg instanceof Error) { const array = Array.prototype.slice.call(arguments) as any[]; array[0] = arg.stack; - this._log(LogLevel.Error, this.format(array)); + this.logger.error(this.format(array)); } else { - this._log(LogLevel.Error, this.format(arguments)); + this.logger.error(this.format(arguments)); } } } critical(): void { if (this.getLevel() <= LogLevel.Critical) { - this._log(LogLevel.Critical, this.format(arguments)); + this.logger.critical(this.format(arguments)); } } dispose(): void { - if (this._logger) { - this.disposeLogger(); - } else if (this._loggerCreationPromise) { - this._loggerCreationPromise.then(() => this.disposeLogger()); - } - this._loggerCreationPromise = undefined; - } - - private disposeLogger(): void { - if (this._logger) { - this._logger.drop(); - this._logger = undefined; - } + this.logger.drop(); } private format(args: any): string { diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 77ddb65a58..49d8bbc6a4 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -71,15 +71,6 @@ export namespace MarkerSeverity { case Severity.Ignore: return MarkerSeverity.Hint; } } - - export function toSeverity(severity: MarkerSeverity): Severity { - switch (severity) { - case MarkerSeverity.Error: return Severity.Error; - case MarkerSeverity.Warning: return Severity.Warning; - case MarkerSeverity.Info: return Severity.Info; - case MarkerSeverity.Hint: return Severity.Ignore; - } - } } /** diff --git a/src/vs/platform/notification/common/notification.ts b/src/vs/platform/notification/common/notification.ts index 0451959be9..926016c982 100644 --- a/src/vs/platform/notification/common/notification.ts +++ b/src/vs/platform/notification/common/notification.ts @@ -4,10 +4,9 @@ *--------------------------------------------------------------------------------------------*/ import BaseSeverity from 'vs/base/common/severity'; -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IAction } from 'vs/base/common/actions'; import { Event, Emitter } from 'vs/base/common/event'; -import { IDisposable } from 'vs/base/common/lifecycle'; export import Severity = BaseSeverity; @@ -70,14 +69,14 @@ export interface INotificationActions { * Primary actions show up as buttons as part of the message and will close * the notification once clicked. */ - primary?: ReadonlyArray; + primary?: IAction[]; /** * Secondary actions are meant to provide additional configuration or context * for the notification and will show up less prominent. A notification does not * close automatically when invoking a secondary action. */ - secondary?: ReadonlyArray; + secondary?: IAction[]; } export interface INotificationProgress { @@ -173,21 +172,6 @@ export interface IPromptOptions extends INotificationProperties { onCancel?: () => void; } -export interface IStatusMessageOptions { - - /** - * An optional timeout after which the status message should show. By default - * the status message will show immediately. - */ - showAfter?: number; - - /** - * An optional timeout after which the status message is to be hidden. By default - * the status message will not hide until another status message is displayed. - */ - hideAfter?: number; -} - /** * A service to bring up notifications and non-modal prompts. * @@ -195,7 +179,7 @@ export interface IStatusMessageOptions { */ export interface INotificationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; /** * Show the provided notification to the user. The returned `INotificationHandle` @@ -237,24 +221,16 @@ export interface INotificationService { * @returns a handle on the notification to e.g. hide it or update message, buttons, etc. */ prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle; - - /** - * Shows a status message in the status area with the provied text. - * - * @param message the message to show as status - * @param options provides some optional configuration options - * - * @returns a disposable to hide the status message - */ - status(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable; } export class NoOpNotification implements INotificationHandle { - readonly progress = new NoOpProgress(); private readonly _onDidClose: Emitter = new Emitter(); - get onDidClose(): Event { return this._onDidClose.event; } + + get onDidClose(): Event { + return this._onDidClose.event; + } updateSeverity(severity: Severity): void { } updateMessage(message: NotificationMessage): void { } diff --git a/src/vs/platform/notification/test/common/testNotificationService.ts b/src/vs/platform/notification/test/common/testNotificationService.ts index 9a00472d7c..7f6ec1ef9f 100644 --- a/src/vs/platform/notification/test/common/testNotificationService.ts +++ b/src/vs/platform/notification/test/common/testNotificationService.ts @@ -3,36 +3,31 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; -import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; +import { INotificationService, INotificationHandle, NoOpNotification, Severity, INotification, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; export class TestNotificationService implements INotificationService { - _serviceBrand: any; + public _serviceBrand: any; private static readonly NO_OP: INotificationHandle = new NoOpNotification(); - info(message: string): INotificationHandle { + public info(message: string): INotificationHandle { return this.notify({ severity: Severity.Info, message }); } - warn(message: string): INotificationHandle { + public warn(message: string): INotificationHandle { return this.notify({ severity: Severity.Warning, message }); } - error(error: string | Error): INotificationHandle { + public error(error: string | Error): INotificationHandle { return this.notify({ severity: Severity.Error, message: error }); } - notify(notification: INotification): INotificationHandle { + public notify(notification: INotification): INotificationHandle { return TestNotificationService.NO_OP; } - prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { + public prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { return TestNotificationService.NO_OP; } - - status(message: string | Error, options?: IStatusMessageOptions): IDisposable { - return Disposable.None; - } } \ No newline at end of file diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index b25f1799b2..5f47886895 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -10,13 +10,8 @@ export const IProductService = createDecorator('productService' export interface IProductService { _serviceBrand: any; - version: string; + version?: string; commit?: string; - nameLong: string; - urlProtocol: string; - extensionAllowedProposedApi: string[]; - uiExtensions?: string[]; - enableTelemetry: boolean; } diff --git a/src/vs/platform/product/node/product.ts b/src/vs/platform/product/node/product.ts index 4ecce8cf13..b06984c69f 100644 --- a/src/vs/platform/product/node/product.ts +++ b/src/vs/platform/product/node/product.ts @@ -81,6 +81,7 @@ export interface IProductConfiguration { hockeyApp: { 'win32-ia32': string; 'win32-x64': string; + 'linux-ia32': string; 'linux-x64': string; 'darwin': string; }; diff --git a/src/vs/platform/product/node/productService.ts b/src/vs/platform/product/node/productService.ts index 66f5e6504c..45deb8e564 100644 --- a/src/vs/platform/product/node/productService.ts +++ b/src/vs/platform/product/node/productService.ts @@ -11,17 +11,9 @@ export class ProductService implements IProductService { _serviceBrand: any; - get version(): string { return pkg.version; } + get version(): string | undefined { return pkg.version; } get commit(): string | undefined { return product.commit; } - get nameLong(): string { return product.nameLong; } - - get urlProtocol(): string { return product.urlProtocol; } - - get extensionAllowedProposedApi(): string[] { return product.extensionAllowedProposedApi; } - - get uiExtensions(): string[] | undefined { return product.uiExtensions; } - get enableTelemetry(): boolean { return product.enableTelemetry; } } diff --git a/src/vs/platform/progress/common/progress.ts b/src/vs/platform/progress/common/progress.ts index 17b6b6e1c2..b605d13714 100644 --- a/src/vs/platform/progress/common/progress.ts +++ b/src/vs/platform/progress/common/progress.ts @@ -3,32 +3,15 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { IAction } from 'vs/base/common/actions'; export const IProgressService = createDecorator('progressService'); -/** - * A progress service that can be used to report progress to various locations of the UI. - */ export interface IProgressService { - - _serviceBrand: ServiceIdentifier; - - withProgress(options: IProgressOptions | IProgressNotificationOptions | IProgressCompositeOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise; -} - -export const ILocalProgressService = createDecorator('localProgressService'); - -/** - * A progress service that will report progress local to the UI piece triggered from. E.g. - * if used from an action of a viewlet, the progress will be reported in that viewlet. - */ -export interface ILocalProgressService { - - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; /** * Show progress customized with the provided flags. @@ -61,14 +44,9 @@ export interface IProgressOptions { } export interface IProgressNotificationOptions extends IProgressOptions { - readonly location: ProgressLocation.Notification; - readonly primaryActions?: ReadonlyArray; - readonly secondaryActions?: ReadonlyArray; -} - -export interface IProgressCompositeOptions extends IProgressOptions { - location: ProgressLocation.Explorer | ProgressLocation.Extensions | ProgressLocation.Scm | string; - delay?: number; + location: ProgressLocation.Notification; + primaryActions?: IAction[]; + secondaryActions?: IAction[]; } export interface IProgressStep { @@ -76,6 +54,15 @@ export interface IProgressStep { increment?: number; } +export const IProgressService2 = createDecorator('progressService2'); + +export interface IProgressService2 { + + _serviceBrand: any; + + withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise; +} + export interface IProgressRunner { total(value: number): void; worked(value: number): void; @@ -131,7 +118,7 @@ export class LongRunningOperation { private currentProgressTimeout: any; constructor( - private localProgressService: ILocalProgressService + private progressService: IProgressService ) { } start(progressDelay: number): IOperation { @@ -144,7 +131,7 @@ export class LongRunningOperation { const newOperationToken = new CancellationTokenSource(); this.currentProgressTimeout = setTimeout(() => { if (newOperationId === this.currentOperationId) { - this.currentProgressRunner = this.localProgressService.show(true); + this.currentProgressRunner = this.progressService.show(true); } }, progressDelay); diff --git a/src/vs/platform/registry/common/platform.ts b/src/vs/platform/registry/common/platform.ts index 9049e880ed..04c360723a 100644 --- a/src/vs/platform/registry/common/platform.ts +++ b/src/vs/platform/registry/common/platform.ts @@ -31,22 +31,26 @@ export interface IRegistry { class RegistryImpl implements IRegistry { - private readonly data = new Map(); + private data: { [id: string]: any; }; + + constructor() { + this.data = {}; + } public add(id: string, data: any): void { Assert.ok(Types.isString(id)); Assert.ok(Types.isObject(data)); - Assert.ok(!this.data.has(id), 'There is already an extension with this id'); + Assert.ok(!this.data.hasOwnProperty(id), 'There is already an extension with this id'); - this.data.set(id, data); + this.data[id] = data; } public knows(id: string): boolean { - return this.data.has(id); + return this.data.hasOwnProperty(id); } public as(id: string): any { - return this.data.get(id) || null; + return this.data[id] || null; } } diff --git a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts index 02f066378e..3bc199103c 100644 --- a/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts +++ b/src/vs/platform/remote/browser/remoteAuthorityResolverService.ts @@ -21,11 +21,14 @@ export class RemoteAuthorityResolverService implements IRemoteAuthorityResolverS } clearResolvedAuthority(authority: string): void { + throw new Error(`Not implemented`); } setResolvedAuthority(resolvedAuthority: ResolvedAuthority) { + throw new Error(`Not implemented`); } setResolvedAuthorityError(authority: string, err: any): void { + throw new Error(`Not implemented`); } } diff --git a/src/vs/platform/request/node/requestService.ts b/src/vs/platform/request/node/requestService.ts index 60eade54f4..c3654c6e1f 100644 --- a/src/vs/platform/request/node/requestService.ts +++ b/src/vs/platform/request/node/requestService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { IRequestOptions, IRequestContext, IRequestFunction, request } from 'vs/base/node/request'; import { getProxyAgent } from 'vs/base/node/proxy'; @@ -16,21 +16,21 @@ import { CancellationToken } from 'vs/base/common/cancellation'; * This service exposes the `request` API, while using the global * or configured proxy settings. */ -export class RequestService extends Disposable implements IRequestService { +export class RequestService implements IRequestService { _serviceBrand: any; private proxyUrl?: string; private strictSSL: boolean; private authorization?: string; + private disposables: IDisposable[] = []; constructor( @IConfigurationService configurationService: IConfigurationService, @ILogService private readonly logService: ILogService ) { - super(); this.configure(configurationService.getValue()); - this._register(configurationService.onDidChangeConfiguration(() => this.configure(configurationService.getValue()), this)); + configurationService.onDidChangeConfiguration(() => this.configure(configurationService.getValue()), this, this.disposables); } private configure(config: IHTTPConfiguration) { diff --git a/src/vs/platform/severityIcon/common/severityIcon.ts b/src/vs/platform/severityIcon/common/severityIcon.ts deleted file mode 100644 index cb40532c65..0000000000 --- a/src/vs/platform/severityIcon/common/severityIcon.ts +++ /dev/null @@ -1,73 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import Severity from 'vs/base/common/severity'; -import { registerThemingParticipant, ITheme, LIGHT } from 'vs/platform/theme/common/themeService'; -import { Color } from 'vs/base/common/color'; - -const errorStart = encodeURIComponent(``); -const errorDarkStart = encodeURIComponent(``); - -const warningStart = encodeURIComponent(``); -const warningDarkStart = encodeURIComponent(``); - -const infoStart = encodeURIComponent(``); -const infoDarkStart = encodeURIComponent(``); - -export namespace SeverityIcon { - - export function getSVGData(severity: Severity, theme: ITheme): string { - switch (severity) { - case Severity.Ignore: - const ignoreColor = theme.type === LIGHT ? Color.fromHex('#1BA1E2') : Color.fromHex('#1BA1E2'); - return theme.type === LIGHT ? infoStart + encodeURIComponent(ignoreColor.toString()) + infoEnd - : infoDarkStart + encodeURIComponent(ignoreColor.toString()) + infoDarkEnd; - case Severity.Info: - const infoColor = theme.type === LIGHT ? Color.fromHex('#1BA1E2') : Color.fromHex('#1BA1E2'); - return theme.type === LIGHT ? infoStart + encodeURIComponent(infoColor.toString()) + infoEnd - : infoDarkStart + encodeURIComponent(infoColor.toString()) + infoDarkEnd; - case Severity.Warning: - const warningColor = theme.type === LIGHT ? Color.fromHex('#fc0') : Color.fromHex('#fc0'); - return theme.type === LIGHT ? warningStart + encodeURIComponent(warningColor.toString()) + warningEnd - : warningDarkStart + encodeURIComponent(warningColor.toString()) + warningDarkEnd; - case Severity.Error: - const errorColor = theme.type === LIGHT ? Color.fromHex('#E51400') : Color.fromHex('#F48771'); - return theme.type === LIGHT ? errorStart + encodeURIComponent(errorColor.toString()) + errorEnd - : errorDarkStart + encodeURIComponent(errorColor.toString()) + errorDarkEnd; - } - return ''; - } - - export function className(severity: Severity): string { - switch (severity) { - case Severity.Ignore: - return 'severity-icon severity-ignore'; - case Severity.Info: - return 'severity-icon severity-info'; - case Severity.Warning: - return 'severity-icon severity-warning'; - case Severity.Error: - return 'severity-icon severity-error'; - } - return ''; - } -} - -function getCSSRule(severity: Severity, theme: ITheme): string { - return `.${SeverityIcon.className(severity).split(' ').join('.')} { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(severity, theme)}") center center no-repeat; height: 16px; width: 16px; }`; -} - -registerThemingParticipant((theme, collector) => { - collector.addRule(getCSSRule(Severity.Error, theme)); - collector.addRule(getCSSRule(Severity.Warning, theme)); - collector.addRule(getCSSRule(Severity.Info, theme)); - collector.addRule(getCSSRule(Severity.Ignore, theme)); -}); \ No newline at end of file diff --git a/src/vs/platform/state/node/stateService.ts b/src/vs/platform/state/node/stateService.ts index 1c65b9a896..b853abd108 100644 --- a/src/vs/platform/state/node/stateService.ts +++ b/src/vs/platform/state/node/stateService.ts @@ -27,36 +27,27 @@ export class FileStorage { } async init(): Promise { - if (this._database) { - return; // return if database was already loaded - } - - const database = await this.loadAsync(); - - if (this._database) { - return; // return if database was already loaded - } - - this._database = database; - } - - private loadSync(): object { try { - this.lastFlushedSerializedDatabase = fs.readFileSync(this.dbPath).toString(); + const contents = await readFile(this.dbPath); - return JSON.parse(this.lastFlushedSerializedDatabase); + try { + this.lastFlushedSerializedDatabase = contents.toString(); + this._database = JSON.parse(this.lastFlushedSerializedDatabase); + } catch (error) { + this._database = {}; + } } catch (error) { if (error.code !== 'ENOENT') { this.onError(error); } - return {}; + this._database = {}; } } - private async loadAsync(): Promise { + private loadSync(): object { try { - this.lastFlushedSerializedDatabase = (await readFile(this.dbPath)).toString(); + this.lastFlushedSerializedDatabase = fs.readFileSync(this.dbPath).toString(); return JSON.parse(this.lastFlushedSerializedDatabase); } catch (error) { diff --git a/src/vs/platform/statusbar/common/statusbar.ts b/src/vs/platform/statusbar/common/statusbar.ts index e95e4adf62..cd7f01e10a 100644 --- a/src/vs/platform/statusbar/common/statusbar.ts +++ b/src/vs/platform/statusbar/common/statusbar.ts @@ -3,15 +3,15 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IDisposable } from 'vs/base/common/lifecycle'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export const IStatusbarService = createDecorator('statusbarService'); export const enum StatusbarAlignment { - LEFT, - RIGHT + LEFT, RIGHT } /** @@ -51,6 +51,11 @@ export interface IStatusbarEntry { */ readonly arguments?: any[]; + /** + * An optional extension ID if this entry is provided from an extension. + */ + readonly extensionId?: ExtensionIdentifier; + /** * Wether to show a beak above the status bar entry. */ @@ -59,24 +64,18 @@ export interface IStatusbarEntry { export interface IStatusbarService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; /** * Adds an entry to the statusbar with the given alignment and priority. Use the returned accessor * to update or remove the statusbar entry. - * - * @param id identifier of the entry is needed to allow users to hide entries via settings - * @param name human readable name the entry is about - * @param alignment either LEFT or RIGHT - * @param priority items get arranged from highest priority to lowest priority from left to right - * in their respective alignment slot */ - addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor; + addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority?: number): IStatusbarEntryAccessor; /** - * Allows to update an entry's visibilty with the provided ID. + * Prints something to the status bar area with optional auto dispose and delay. */ - updateEntryVisibility(id: string, visible: boolean): void; + setStatusMessage(message: string, autoDisposeAfter?: number, delayBy?: number): IDisposable; } export interface IStatusbarEntryAccessor extends IDisposable { diff --git a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts index aeab37b081..e92747789c 100644 --- a/src/vs/platform/telemetry/node/workbenchCommonProperties.ts +++ b/src/vs/platform/telemetry/node/workbenchCommonProperties.ts @@ -14,7 +14,7 @@ export const lastSessionDateStorageKey = 'telemetry.lastSessionDate'; // {{ SQL CARBON EDIT }} import product from 'vs/platform/product/node/product'; -export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string, remoteAuthority?: string): Promise<{ [name: string]: string | undefined }> { +export async function resolveWorkbenchCommonProperties(storageService: IStorageService, commit: string | undefined, version: string | undefined, machineId: string, installSourcePath: string): Promise<{ [name: string]: string | undefined }> { const result = await resolveCommonProperties(commit, version, machineId, installSourcePath); const instanceId = storageService.get(instanceStorageKey, StorageScope.GLOBAL)!; const firstSessionDate = storageService.get(firstSessionDateStorageKey, StorageScope.GLOBAL)!; @@ -32,9 +32,11 @@ export async function resolveWorkbenchCommonProperties(storageService: IStorageS // result['common.isNewSession'] = !lastSessionDate ? '1' : '0'; // __GDPR__COMMON__ "common.instanceId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } // result['common.instanceId'] = instanceId; - // __GDPR__COMMON__ "common.remoteAuthority" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - // result['common.remoteAuthority'] = cleanRemoteAuthority(remoteAuthority); + // __GDPR__COMMON__ "common.version.shell" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + result['common.version.shell'] = process.versions && process.versions['electron']; + // __GDPR__COMMON__ "common.version.renderer" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + result['common.version.renderer'] = process.versions && process.versions['chrome']; // {{SQL CARBON EDIT}} result['common.application.name'] = product.nameLong; // {{SQL CARBON EDIT}} @@ -60,20 +62,5 @@ function setUsageDates(storageService: IStorageService): void { // monthly last usage date const monthlyLastUseDate = storageService.get('telemetry.monthlyLastUseDate', StorageScope.GLOBAL, appStartDate.toUTCString()); storageService.store('telemetry.monthlyLastUseDate', monthlyLastUseDate, StorageScope.GLOBAL); -} - -function cleanRemoteAuthority(remoteAuthority?: string): string { - if (!remoteAuthority) { - return 'none'; - } - - let ret = 'other'; - // Whitelisted remote authorities - ['ssh-remote', 'dev-container', 'wsl'].forEach((res: string) => { - if (remoteAuthority!.indexOf(`${res}+`) === 0) { - ret = res; - } - }); - - return ret; + } diff --git a/src/vs/platform/theme/common/colorRegistry.ts b/src/vs/platform/theme/common/colorRegistry.ts index 5f42216ccb..5a01929b64 100644 --- a/src/vs/platform/theme/common/colorRegistry.ts +++ b/src/vs/platform/theme/common/colorRegistry.ts @@ -266,18 +266,6 @@ export const menuSelectionBackground = registerColor('menu.selectionBackground', export const menuSelectionBorder = registerColor('menu.selectionBorder', { dark: null, light: null, hc: activeContrastBorder }, nls.localize('menuSelectionBorder', "Border color of the selected menu item in menus.")); export const menuSeparatorBackground = registerColor('menu.separatorBackground', { dark: '#BBBBBB', light: '#888888', hc: contrastBorder }, nls.localize('menuSeparatorBackground', "Color of a separator menu item in menus.")); -export const editorErrorForeground = registerColor('editorError.foreground', { dark: '#F48771', light: '#E51400', hc: null }, nls.localize('editorError.foreground', 'Foreground color of error squigglies in the editor.')); -export const editorErrorBorder = registerColor('editorError.border', { dark: null, light: null, hc: Color.fromHex('#E47777').transparent(0.8) }, nls.localize('errorBorder', 'Border color of error boxes in the editor.')); - -export const editorWarningForeground = registerColor('editorWarning.foreground', { dark: '#FFCC00', light: '#E9A700', hc: null }, nls.localize('editorWarning.foreground', 'Foreground color of warning squigglies in the editor.')); -export const editorWarningBorder = registerColor('editorWarning.border', { dark: null, light: null, hc: Color.fromHex('#FFCC00').transparent(0.8) }, nls.localize('warningBorder', 'Border color of warning boxes in the editor.')); - -export const editorInfoForeground = registerColor('editorInfo.foreground', { dark: '#008000', light: '#008000', hc: null }, nls.localize('editorInfo.foreground', 'Foreground color of info squigglies in the editor.')); -export const editorInfoBorder = registerColor('editorInfo.border', { dark: null, light: null, hc: Color.fromHex('#71B771').transparent(0.8) }, nls.localize('infoBorder', 'Border color of info boxes in the editor.')); - -export const editorHintForeground = registerColor('editorHint.foreground', { dark: Color.fromHex('#eeeeee').transparent(0.7), light: '#6c6c6c', hc: null }, nls.localize('editorHint.foreground', 'Foreground color of hint squigglies in the editor.')); -export const editorHintBorder = registerColor('editorHint.border', { dark: null, light: null, hc: Color.fromHex('#eeeeee').transparent(0.8) }, nls.localize('hintBorder', 'Border color of hint boxes in the editor.')); - /** * Editor background color. * Because of bug https://monacotools.visualstudio.com/DefaultCollection/Monaco/_workitems/edit/13254 diff --git a/src/vs/platform/theme/common/styler.ts b/src/vs/platform/theme/common/styler.ts index 31b5c9282f..479077ef30 100644 --- a/src/vs/platform/theme/common/styler.ts +++ b/src/vs/platform/theme/common/styler.ts @@ -351,4 +351,4 @@ export const defaultDialogStyles = { export function attachDialogStyler(widget: IThemable, themeService: IThemeService, style?: IDialogStyleOverrides): IDisposable { return attachStyler(themeService, { ...defaultDialogStyles, ...style }, widget); -} \ No newline at end of file +} diff --git a/src/vs/platform/theme/electron-main/themeMainService.ts b/src/vs/platform/theme/electron-main/themeMainService.ts deleted file mode 100644 index 0ff6648cac..0000000000 --- a/src/vs/platform/theme/electron-main/themeMainService.ts +++ /dev/null @@ -1,67 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { isWindows, isMacintosh } from 'vs/base/common/platform'; -import { systemPreferences, ipcMain as ipc } from 'electron'; -import { IStateService } from 'vs/platform/state/common/state'; -import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; - -const DEFAULT_BG_LIGHT = '#FFFFFF'; -const DEFAULT_BG_DARK = '#1E1E1E'; -const DEFAULT_BG_HC_BLACK = '#000000'; - -const THEME_STORAGE_KEY = 'theme'; -const THEME_BG_STORAGE_KEY = 'themeBackground'; - -export const IThemeMainService = createDecorator('themeMainService'); - -export interface IThemeMainService { - _serviceBrand: any; - - getBackgroundColor(): string; -} - -export class ThemeMainService implements IThemeMainService { - - _serviceBrand: any; - - constructor(@IStateService private stateService: IStateService) { - ipc.on('vscode:changeColorTheme', (e: Event, windowId: number, broadcast: string) => { - // Theme changes - if (typeof broadcast === 'string') { - this.storeBackgroundColor(JSON.parse(broadcast)); - } - }); - } - - private storeBackgroundColor(data: { baseTheme: string, background: string }): void { - this.stateService.setItem(THEME_STORAGE_KEY, data.baseTheme); - this.stateService.setItem(THEME_BG_STORAGE_KEY, data.background); - } - - public getBackgroundColor(): string { - if (isWindows && systemPreferences.isInvertedColorScheme()) { - return DEFAULT_BG_HC_BLACK; - } - - let background = this.stateService.getItem(THEME_BG_STORAGE_KEY, null); - if (!background) { - let baseTheme: string; - if (isWindows && systemPreferences.isInvertedColorScheme()) { - baseTheme = 'hc-black'; - } else { - baseTheme = this.stateService.getItem(THEME_STORAGE_KEY, 'vs-dark').split(' ')[0]; - } - - background = (baseTheme === 'hc-black') ? DEFAULT_BG_HC_BLACK : (baseTheme === 'vs' ? DEFAULT_BG_LIGHT : DEFAULT_BG_DARK); - } - - if (isMacintosh && background.toUpperCase() === DEFAULT_BG_DARK) { - background = '#171717'; // https://github.com/electron/electron/issues/5150 - } - - return background; - } -} \ No newline at end of file diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 0431b53683..c4a6f6d947 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -239,10 +239,10 @@ export class Win32UpdateService extends AbstractUpdateService { }); const readyMutexName = `${product.win32MutexName}-ready`; - const mutex = await import('windows-mutex'); + const isActive = (require.__$__nodeRequire('windows-mutex') as any).isActive; // poll for mutex-ready - pollUntil(() => mutex.isActive(readyMutexName)) + pollUntil(() => isActive(readyMutexName)) .then(() => this.setState(State.Ready(update))); } diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index 94bd4e509c..d9843090f2 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -6,7 +6,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry'; -import { IProcessEnvironment, isMacintosh, isLinux, isWeb } from 'vs/base/common/platform'; +import { IProcessEnvironment, isMacintosh, isLinux } from 'vs/base/common/platform'; import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; @@ -282,10 +282,6 @@ export interface IWindowSettings { } export function getTitleBarStyle(configurationService: IConfigurationService, environment: IEnvironmentService, isExtensionDevelopment = environment.isExtensionDevelopment): 'native' | 'custom' { - if (isWeb) { - return 'custom'; - } - const configuration = configurationService.getValue('window'); const isDev = !environment.isBuilt || isExtensionDevelopment; diff --git a/src/vs/platform/windows/electron-main/windows.ts b/src/vs/platform/windows/electron-main/windows.ts index 88b695be11..45d6fd87a2 100644 --- a/src/vs/platform/windows/electron-main/windows.ts +++ b/src/vs/platform/windows/electron-main/windows.ts @@ -92,6 +92,7 @@ export interface IWindowsMainService { readonly onWindowClose: Event; // methods + ready(initialUserEnv: IProcessEnvironment): void; reload(win: ICodeWindow, cli?: ParsedArgs): void; enterWorkspace(win: ICodeWindow, path: URI): Promise; closeWorkspace(win: ICodeWindow): void; diff --git a/src/vs/platform/windows/electron-main/windowsService.ts b/src/vs/platform/windows/electron-main/windowsService.ts index f73f47ccc3..b0140617f5 100644 --- a/src/vs/platform/windows/electron-main/windowsService.ts +++ b/src/vs/platform/windows/electron-main/windowsService.ts @@ -403,20 +403,19 @@ export class WindowsService implements IWindowsService, IURLHandler, IDisposable buttons = [ok, copy]; } - const result = await this.windowsMainService.showMessageBox({ + this.windowsMainService.showMessageBox({ title: product.nameLong, type: 'info', message: product.nameLong, detail: `\n${detail}`, buttons, noLink: true, - defaultId: buttons.indexOf(ok), - cancelId: buttons.indexOf(ok) - }, this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow()); - - if (buttons[result.button] === copy) { - clipboard.writeText(detail); - } + defaultId: buttons.indexOf(ok) + }, this.windowsMainService.getFocusedWindow() || this.windowsMainService.getLastActiveWindow()).then(result => { + if (buttons[result.button] === copy) { + clipboard.writeText(detail); + } + }); } async handleURL(uri: URI): Promise { diff --git a/src/vs/platform/workspace/common/workspace.ts b/src/vs/platform/workspace/common/workspace.ts index 0908b46335..f654292fca 100644 --- a/src/vs/platform/workspace/common/workspace.ts +++ b/src/vs/platform/workspace/common/workspace.ts @@ -228,7 +228,7 @@ export function toWorkspaceFolder(resource: URI): WorkspaceFolder { export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], workspaceConfigFile: URI): WorkspaceFolder[] { let result: WorkspaceFolder[] = []; - let seen: Set = new Set(); + let seen: { [uri: string]: boolean } = Object.create(null); const relativeTo = resources.dirname(workspaceConfigFile); for (let configuredFolder of configuredFolders) { @@ -252,8 +252,8 @@ export function toWorkspaceFolders(configuredFolders: IStoredWorkspaceFolder[], if (uri) { // remove duplicates let comparisonKey = resources.getComparisonKey(uri); - if (!seen.has(comparisonKey)) { - seen.add(comparisonKey); + if (!seen[comparisonKey]) { + seen[comparisonKey] = true; const name = configuredFolder.name || resources.basenameOrAuthority(uri); result.push(new WorkspaceFolder({ uri, name, index: result.length }, configuredFolder)); diff --git a/src/vs/vscode.d.ts b/src/vs/vscode.d.ts index 9d1a2892ca..6783daf65e 100644 --- a/src/vs/vscode.d.ts +++ b/src/vs/vscode.d.ts @@ -1101,7 +1101,7 @@ declare module 'vscode' { /** * The column in which this editor shows. Will be `undefined` in case this - * isn't one of the main editors, e.g. an embedded editor, or when the editor + * isn't one of the main editors, e.g an embedded editor, or when the editor * column is larger than three. */ viewColumn?: ViewColumn; @@ -1900,7 +1900,7 @@ declare module 'vscode' { * * *Note* that a document selector that is just a language identifier selects *all* * documents, even those that are not saved on disk. Only use such selectors when - * a feature works without further context, e.g. without the need to resolve related + * a feature works without further context, e.g without the need to resolve related * 'files'. * * @sample `let sel:DocumentSelector = { scheme: 'file', language: 'typescript' }`; @@ -2595,7 +2595,7 @@ declare module 'vscode' { name: string; /** - * More detail for this symbol, e.g. the signature of a function. + * More detail for this symbol, e.g the signature of a function. */ detail: string; @@ -2605,12 +2605,12 @@ declare module 'vscode' { kind: SymbolKind; /** - * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + * The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g comments and code. */ range: Range; /** - * The range that should be selected and reveal when this symbol is being picked, e.g. the name of a function. + * The range that should be selected and reveal when this symbol is being picked, e.g the name of a function. * Must be contained by the [`range`](#DocumentSymbol.range). */ selectionRange: Range; @@ -3515,10 +3515,6 @@ declare module 'vscode' { * * The editor will only resolve a completion item once. * - * *Note* that accepting a completion item will not wait for it to be resolved. Because of that [`insertText`](#CompletionItem.insertText), - * [`additionalTextEdits`](#CompletionItem.additionalTextEdits), and [`command`](#CompletionItem.command) should not - * be changed when resolving an item. - * * @param item A completion item currently active in the UI. * @param token A cancellation token. * @return The resolved completion item or a thenable that resolves to of such. It is OK to return the given @@ -3649,7 +3645,7 @@ declare module 'vscode' { * * For some languages one color can have multiple presentations, e.g. css can represent the color red with * the constant `Red`, the hex-value `#ff0000`, or in rgba and hsla forms. In csharp other representations - * apply, e.g. `System.Drawing.Color.Red`. + * apply, e.g `System.Drawing.Color.Red`. */ export class ColorPresentation { @@ -4235,7 +4231,7 @@ declare module 'vscode' { /** * Represents a related message and source code location for a diagnostic. This should be - * used to point to code locations that cause or related to a diagnostics, e.g. when duplicating + * used to point to code locations that cause or related to a diagnostics, e.g when duplicating * a symbol in a scope. */ export class DiagnosticRelatedInformation { @@ -6680,7 +6676,7 @@ declare module 'vscode' { * the following rules: * * - The uri-scheme must be `vscode.env.uriScheme`; - * - The uri-authority must be the extension id (e.g. `my.extension`); + * - The uri-authority must be the extension id (eg. `my.extension`); * - The uri-path, -query and -fragment parts are arbitrary. * * For example, if the `my.extension` extension registers a uri handler, it will only @@ -8421,9 +8417,9 @@ declare module 'vscode' { /** * Creates a new [source control](#SourceControl) instance. * - * @param id An `id` for the source control. Something short, e.g.: `git`. - * @param label A human-readable string for the source control. E.g.: `Git`. - * @param rootUri An optional Uri of the root of the source control. E.g.: `Uri.parse(workspaceRoot)`. + * @param id An `id` for the source control. Something short, eg: `git`. + * @param label A human-readable string for the source control. Eg: `Git`. + * @param rootUri An optional Uri of the root of the source control. Eg: `Uri.parse(workspaceRoot)`. * @return An instance of [source control](#SourceControl). */ export function createSourceControl(id: string, label: string, rootUri?: Uri): SourceControl; @@ -8987,7 +8983,7 @@ declare module 'vscode' { /** * The uri of the document the thread has been created on. */ - readonly uri: Uri; + readonly resource: Uri; /** * The range the comment thread is located within the document. The thread icon will be shown @@ -9101,7 +9097,7 @@ declare module 'vscode' { } /** - * Command argument for actions registered in `comments/commentThread/context`. + * Command argument for actions registered in `comments/commentThread/actions`. */ export interface CommentReply { /** @@ -9151,7 +9147,7 @@ declare module 'vscode' { * Create a [comment thread](#CommentThread). The comment thread will be displayed in visible text editors (if the resource matches) * and Comments Panel once created. * - * @param uri The uri of the document the thread has been created on. + * @param resource The uri of the document the thread has been created on. * @param range The range the comment thread is located within the document. * @param comments The ordered comments of the thread. */ diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index ed028a55a2..7ef9a092db 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -137,20 +137,32 @@ declare module 'vscode' { // #region Joh - code insets - export interface WebviewEditorInset { - readonly editor: TextEditor; - readonly range: Range; - readonly webview: Webview; - readonly onDidDispose: Event; - dispose(): void; + /** + */ + export class CodeInset { + range: Range; + height?: number; + constructor(range: Range, height?: number); } - export namespace window { - export function createWebviewTextEditorInset(editor: TextEditor, range: Range, options?: WebviewOptions): WebviewEditorInset; + export interface CodeInsetProvider { + onDidChangeCodeInsets?: Event; + provideCodeInsets(document: TextDocument, token: CancellationToken): ProviderResult; + resolveCodeInset(codeInset: CodeInset, webview: Webview, token: CancellationToken): ProviderResult; + } + + export namespace languages { + + /** + * Register a code inset provider. + * + */ + export function registerCodeInsetProvider(selector: DocumentSelector, provider: CodeInsetProvider): Disposable; } //#endregion + //#region Joh - read/write in chunks export interface FileSystemProvider { @@ -1051,7 +1063,7 @@ declare module 'vscode' { * @param range The range the comment thread is located within the document. * @param comments The ordered comments of the thread. */ - createCommentThread(id: string, resource: Uri, range: Range, comments: Comment[]): CommentThread; + createCommentThread(id: string, uri: Uri, range: Range, comments: Comment[]): CommentThread; /** * Optional new comment thread factory. @@ -1087,17 +1099,6 @@ declare module 'vscode' { //#region Terminal - export interface TerminalOptions { - /** - * When enabled the terminal will run the process as normal but not be surfaced to the user - * until `Terminal.show` is called. The typical usage for this is when you need to run - * something that may need interactivity but only want to tell the user about it when - * interaction is needed. Note that the terminals will still be exposed to all extensions - * as normal. - */ - runInBackground?: boolean; - } - /** * An [event](#Event) which fires when a [Terminal](#Terminal)'s dimensions change. */ @@ -1425,18 +1426,4 @@ declare module 'vscode' { //#endregion - //#region DocumentLink tooltip mjbvz - - interface DocumentLink { - /** - * The tooltip text when you hover over this link. - * - * If a tooltip is provided, is will be displayed in a string that includes instructions on how to - * trigger the link, such as `cmd + click to {0}`. The specific instructions vary depending on OS, - * user settings, and localization. - */ - tooltip?: string; - } - - // #endregion } diff --git a/src/vs/workbench/api/browser/mainThreadClipboard.ts b/src/vs/workbench/api/browser/mainThreadClipboard.ts index 94ae9eff39..2cd50d1214 100644 --- a/src/vs/workbench/api/browser/mainThreadClipboard.ts +++ b/src/vs/workbench/api/browser/mainThreadClipboard.ts @@ -8,7 +8,7 @@ import { MainContext, MainThreadClipboardShape } from '../common/extHost.protoco import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; @extHostNamedCustomer(MainContext.MainThreadClipboard) -export class MainThreadClipboard implements MainThreadClipboardShape { +export class MainThreadCommands implements MainThreadClipboardShape { constructor( _context: any, diff --git a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts b/src/vs/workbench/api/browser/mainThreadCodeInsets.ts deleted file mode 100644 index f26bd86290..0000000000 --- a/src/vs/workbench/api/browser/mainThreadCodeInsets.ts +++ /dev/null @@ -1,144 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { UriComponents, URI } from 'vs/base/common/uri'; -import * as modes from 'vs/editor/common/modes'; -import { MainContext, MainThreadEditorInsetsShape, IExtHostContext, ExtHostEditorInsetsShape, ExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; -import { extHostNamedCustomer } from '../common/extHostCustomers'; -import { IRange } from 'vs/editor/common/core/range'; -import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; -import { IWebviewService, Webview } from 'vs/workbench/contrib/webview/common/webview'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { IActiveCodeEditor, IViewZone } from 'vs/editor/browser/editorBrowser'; - -// todo@joh move these things back into something like contrib/insets -class EditorWebviewZone implements IViewZone { - - readonly domNode: HTMLElement; - readonly afterLineNumber: number; - readonly afterColumn: number; - readonly heightInLines: number; - - private _id: number; - // suppressMouseDown?: boolean | undefined; - // heightInPx?: number | undefined; - // minWidthInPx?: number | undefined; - // marginDomNode?: HTMLElement | null | undefined; - // onDomNodeTop?: ((top: number) => void) | undefined; - // onComputedHeight?: ((height: number) => void) | undefined; - - constructor( - readonly editor: IActiveCodeEditor, - readonly range: IRange, - readonly webview: Webview, - ) { - this.domNode = document.createElement('div'); - this.afterLineNumber = range.startLineNumber; - this.afterColumn = range.startColumn; - this.heightInLines = range.endLineNumber - range.startLineNumber; - - editor.changeViewZones(accessor => this._id = accessor.addZone(this)); - webview.mountTo(this.domNode); - } - - dispose(): void { - this.editor.changeViewZones(accessor => accessor.removeZone(this._id)); - } -} - -@extHostNamedCustomer(MainContext.MainThreadEditorInsets) -export class MainThreadEditorInsets implements MainThreadEditorInsetsShape { - - private readonly _proxy: ExtHostEditorInsetsShape; - private readonly _disposables = new DisposableStore(); - private readonly _insets = new Map(); - - constructor( - context: IExtHostContext, - @ICodeEditorService private readonly _editorService: ICodeEditorService, - @IWebviewService private readonly _webviewService: IWebviewService, - ) { - this._proxy = context.getProxy(ExtHostContext.ExtHostEditorInsets); - } - - dispose(): void { - this._disposables.dispose(); - } - - async $createEditorInset(handle: number, id: string, uri: UriComponents, range: IRange, options: modes.IWebviewOptions): Promise { - - let editor: IActiveCodeEditor | undefined; - id = id.substr(0, id.indexOf(',')); //todo@joh HACK - - for (const candidate of this._editorService.listCodeEditors()) { - if (candidate.getId() === id && candidate.hasModel() && candidate.getModel()!.uri.toString() === URI.revive(uri).toString()) { - editor = candidate; - break; - } - } - - if (!editor) { - setTimeout(() => this._proxy.$onDidDispose(handle)); - return; - } - - const disposables = new DisposableStore(); - - const webview = this._webviewService.createWebview({ - enableFindWidget: false, - allowSvgs: false, - extension: undefined - }, { - allowScripts: options.enableScripts - }); - - const webviewZone = new EditorWebviewZone(editor, range, webview); - - const remove = () => { - disposables.dispose(); - this._proxy.$onDidDispose(handle); - this._insets.delete(handle); - }; - - disposables.add(editor.onDidChangeModel(remove)); - disposables.add(editor.onDidDispose(remove)); - disposables.add(webviewZone); - disposables.add(webview); - disposables.add(webview.onMessage(msg => this._proxy.$onDidReceiveMessage(handle, msg))); - - this._insets.set(handle, webviewZone); - } - - $disposeEditorInset(handle: number): void { - const inset = this._insets.get(handle); - if (inset) { - this._insets.delete(handle); - inset.dispose(); - } - } - - $setHtml(handle: number, value: string): void { - const inset = this._insets.get(handle); - if (inset) { - inset.webview.html = value; - } - } - - $setOptions(handle: number, options: modes.IWebviewOptions): void { - const inset = this._insets.get(handle); - if (inset) { - inset.webview.options = options; - } - } - - $postMessage(handle: number, value: any): Promise { - const inset = this._insets.get(handle); - if (inset) { - inset.webview.sendMessage(value); - return Promise.resolve(true); - } - return Promise.resolve(false); - } -} diff --git a/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index 625e8c30d0..acf8aa9d87 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -12,7 +12,7 @@ import { revive } from 'vs/base/common/marshalling'; @extHostNamedCustomer(MainContext.MainThreadCommands) export class MainThreadCommands implements MainThreadCommandsShape { - private readonly _commandRegistrations = new Map(); + private readonly _disposables = new Map(); private readonly _generateCommandsDocumentationRegistration: IDisposable; private readonly _proxy: ExtHostCommandsShape; @@ -26,8 +26,8 @@ export class MainThreadCommands implements MainThreadCommandsShape { } dispose() { - this._commandRegistrations.forEach(value => value.dispose()); - this._commandRegistrations.clear(); + this._disposables.forEach(value => value.dispose()); + this._disposables.clear(); this._generateCommandsDocumentationRegistration.dispose(); } @@ -53,7 +53,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { } $registerCommand(id: string): void { - this._commandRegistrations.set( + this._disposables.set( id, CommandsRegistry.registerCommand(id, (accessor, ...args) => { return this._proxy.$executeContributedCommand(id, ...args).then(result => { @@ -64,10 +64,10 @@ export class MainThreadCommands implements MainThreadCommandsShape { } $unregisterCommand(id: string): void { - const command = this._commandRegistrations.get(id); + const command = this._disposables.get(id); if (command) { command.dispose(); - this._commandRegistrations.delete(id); + this._disposables.delete(id); } } diff --git a/src/vs/workbench/api/browser/mainThreadComments.ts b/src/vs/workbench/api/browser/mainThreadComments.ts index 31e5478047..76b910bcd1 100644 --- a/src/vs/workbench/api/browser/mainThreadComments.ts +++ b/src/vs/workbench/api/browser/mainThreadComments.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditor, isCodeEditor, isDiffEditor, IDiffEditor } from 'vs/editor/browser/editorBrowser'; import * as modes from 'vs/editor/common/modes'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; @@ -299,8 +299,7 @@ export class MainThreadCommentController { this._features = features; } - createCommentThread(extensionId: string, - commentThreadHandle: number, + createCommentThread(commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, @@ -308,7 +307,7 @@ export class MainThreadCommentController { let thread = new MainThreadCommentThread( commentThreadHandle, this.handle, - extensionId, + '', threadId, URI.revive(resource).toString(), range @@ -452,10 +451,6 @@ export class MainThreadCommentController { this._proxy.$createCommentThreadTemplate(this.handle, resource, range); } - async updateCommentThreadTemplate(threadHandle: number, range: IRange) { - await this._proxy.$updateCommentThreadTemplate(this.handle, threadHandle, range); - } - toJSON(): any { return { $mid: 6, @@ -466,19 +461,16 @@ export class MainThreadCommentController { @extHostNamedCustomer(MainContext.MainThreadComments) export class MainThreadComments extends Disposable implements MainThreadCommentsShape { + private _disposables: IDisposable[]; + private _activeCommentThreadDisposables: IDisposable[]; private readonly _proxy: ExtHostCommentsShape; private _documentProviders = new Map(); private _workspaceProviders = new Map(); private _handlers = new Map(); private _commentControllers = new Map(); - private _activeCommentThread?: MainThreadCommentThread; - private readonly _activeCommentThreadDisposables = this._register(new DisposableStore()); - private _input?: modes.CommentInput; - private _openPanelListener: IDisposable | null; - constructor( extHostContext: IExtHostContext, @IEditorService private readonly _editorService: IEditorService, @@ -488,27 +480,9 @@ export class MainThreadComments extends Disposable implements MainThreadComments @IConfigurationService private readonly _configurationService: IConfigurationService, ) { super(); + this._disposables = []; + this._activeCommentThreadDisposables = []; this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostComments); - - this._register(this._commentService.onDidChangeActiveCommentThread(async thread => { - let handle = (thread as MainThreadCommentThread).controllerHandle; - let controller = this._commentControllers.get(handle); - - if (!controller) { - return; - } - - this._activeCommentThreadDisposables.clear(); - this._activeCommentThread = thread as MainThreadCommentThread; - controller.activeCommentThread = this._activeCommentThread; - - this._activeCommentThreadDisposables.add(this._activeCommentThread.onDidChangeInput(input => { // todo, dispose - this._input = input; - this._proxy.$onCommentWidgetInputChange(handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread!.range, this._input ? this._input.value : undefined); - })); - - await this._proxy.$onCommentWidgetInputChange(controller.handle, URI.parse(this._activeCommentThread!.resource), this._activeCommentThread.range, this._input ? this._input.value : undefined); - })); } $registerCommentController(handle: number, id: string, label: string): void { @@ -551,8 +525,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments commentThreadHandle: number, threadId: string, resource: UriComponents, - range: IRange, - extensionId: ExtensionIdentifier + range: IRange ): modes.CommentThread2 | undefined { let provider = this._commentControllers.get(handle); @@ -560,7 +533,7 @@ export class MainThreadComments extends Disposable implements MainThreadComments return undefined; } - return provider.createCommentThread(extensionId.value, commentThreadHandle, threadId, resource, range); + return provider.createCommentThread(commentThreadHandle, threadId, resource, range); } $updateCommentThread(handle: number, @@ -780,7 +753,8 @@ export class MainThreadComments extends Disposable implements MainThreadComments } dispose(): void { - super.dispose(); + this._disposables = dispose(this._disposables); + this._activeCommentThreadDisposables = dispose(this._activeCommentThreadDisposables); this._workspaceProviders.forEach(value => dispose(value)); this._workspaceProviders.clear(); this._documentProviders.forEach(value => dispose(value)); diff --git a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts index 923b3a3775..db5ee1e41e 100644 --- a/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts +++ b/src/vs/workbench/api/browser/mainThreadDocumentsAndEditors.ts @@ -176,11 +176,11 @@ class MainThreadDocumentAndEditorStateComputer { } private _onDidAddEditor(e: ICodeEditor): void { - this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable( + this._toDisposeOnEditorRemove.set(e.getId(), combinedDisposable([ e.onDidChangeModel(() => this._updateState()), e.onDidFocusEditorText(() => this._updateState()), e.onDidFocusEditorWidget(() => this._updateState(e)) - )); + ])); this._updateState(); } diff --git a/src/vs/workbench/api/browser/mainThreadKeytar.ts b/src/vs/workbench/api/browser/mainThreadKeytar.ts index 0cd602a1db..6da34102ec 100644 --- a/src/vs/workbench/api/browser/mainThreadKeytar.ts +++ b/src/vs/workbench/api/browser/mainThreadKeytar.ts @@ -5,19 +5,27 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { MainContext, MainThreadKeytarShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol'; -import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import { optional } from 'vs/platform/instantiation/common/instantiation'; + +interface IKeytarModule { + getPassword(service: string, account: string): Promise; + setPassword(service: string, account: string, password: string): Promise; + deletePassword(service: string, account: string): Promise; + findPassword(service: string): Promise; +} @extHostNamedCustomer(MainContext.MainThreadKeytar) export class MainThreadKeytar implements MainThreadKeytarShape { - private readonly _credentialsService?: ICredentialsService; + private _keytar: IKeytarModule | null; constructor( - _extHostContext: IExtHostContext, - @optional(ICredentialsService) credentialsService: ICredentialsService, + extHostContext: IExtHostContext ) { - this._credentialsService = credentialsService; + try { + this._keytar = require.__$__nodeRequire('keytar'); + } catch (e) { + this._keytar = null; + } } dispose(): void { @@ -25,28 +33,28 @@ export class MainThreadKeytar implements MainThreadKeytarShape { } async $getPassword(service: string, account: string): Promise { - if (this._credentialsService) { - return this._credentialsService.getPassword(service, account); + if (this._keytar) { + return this._keytar.getPassword(service, account); } return null; } async $setPassword(service: string, account: string, password: string): Promise { - if (this._credentialsService) { - return this._credentialsService.setPassword(service, account, password); + if (this._keytar) { + return this._keytar.setPassword(service, account, password); } } async $deletePassword(service: string, account: string): Promise { - if (this._credentialsService) { - return this._credentialsService.deletePassword(service, account); + if (this._keytar) { + return this._keytar.deletePassword(service, account); } return false; } async $findPassword(service: string): Promise { - if (this._credentialsService) { - return this._credentialsService.findPassword(service); + if (this._keytar) { + return this._keytar.findPassword(service); } return null; } diff --git a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts index 8170af7995..069778aed8 100644 --- a/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts +++ b/src/vs/workbench/api/browser/mainThreadLanguageFeatures.ts @@ -11,29 +11,34 @@ import * as search from 'vs/workbench/contrib/search/common/search'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Position as EditorPosition } from 'vs/editor/common/core/position'; import { Range as EditorRange, IRange } from 'vs/editor/common/core/range'; -import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CallHierarchyDto, SuggestDataDto, CodeActionDto } from '../common/extHost.protocol'; +import { ExtHostContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, MainContext, IExtHostContext, ISerializedLanguageConfiguration, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, LocationDto, WorkspaceSymbolDto, CodeActionDto, reviveWorkspaceEditDto, ISerializedDocumentFilter, DefinitionLinkDto, ISerializedSignatureHelpProviderMetadata, CodeInsetDto, LinkDto, CallHierarchyDto, SuggestDataDto } from '../common/extHost.protocol'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; import { LanguageConfiguration, IndentationRule, OnEnterRule } from 'vs/editor/common/modes/languageConfiguration'; import { IModeService } from 'vs/editor/common/services/modeService'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; import { Selection } from 'vs/editor/common/core/selection'; +import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import * as callh from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; +import { IHeapService } from 'vs/workbench/services/heap/common/heap'; import { mixin } from 'vs/base/common/objects'; @extHostNamedCustomer(MainContext.MainThreadLanguageFeatures) export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesShape { private readonly _proxy: ExtHostLanguageFeaturesShape; + private readonly _heapService: IHeapService; private readonly _modeService: IModeService; private readonly _registrations: { [handle: number]: IDisposable; } = Object.create(null); constructor( extHostContext: IExtHostContext, + @IHeapService heapService: IHeapService, @IModeService modeService: IModeService, ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostLanguageFeatures); + this._heapService = heapService; this._modeService = modeService; } @@ -96,7 +101,7 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } } - private static _reviveCodeActionDto(data: ReadonlyArray): modes.CodeAction[] { + private static _reviveCodeActionDto(data: CodeActionDto[] | undefined): modes.CodeAction[] { if (data) { data.forEach(code => reviveWorkspaceEditDto(code.edit)); } @@ -135,19 +140,25 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void { const provider = { - provideCodeLenses: (model: ITextModel, token: CancellationToken): Promise => { - return this._proxy.$provideCodeLenses(handle, model.uri, token).then(listDto => { - if (!listDto) { - return undefined; + provideCodeLenses: (model: ITextModel, token: CancellationToken): modes.ICodeLensSymbol[] | Promise => { + return this._proxy.$provideCodeLenses(handle, model.uri, token).then(dto => { + if (dto) { + dto.forEach(obj => { + this._heapService.trackObject(obj); + this._heapService.trackObject(obj.command); + }); } - return { - lenses: listDto.lenses, - dispose: () => listDto.cacheId && this._proxy.$releaseCodeLenses(handle, listDto.cacheId) - }; + return dto; }); }, - resolveCodeLens: (_model: ITextModel, codeLens: modes.CodeLens, token: CancellationToken): Promise => { - return this._proxy.$resolveCodeLens(handle, codeLens, token); + resolveCodeLens: (_model: ITextModel, codeLens: modes.ICodeLensSymbol, token: CancellationToken): Promise => { + return this._proxy.$resolveCodeLens(handle, codeLens, token).then(obj => { + if (obj) { + this._heapService.trackObject(obj); + this._heapService.trackObject(obj.command); + } + return obj; + }); } }; @@ -167,6 +178,35 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha } } + // -- code inset + + $registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number): void { + + const provider = { + provideCodeInsets: (model: ITextModel, token: CancellationToken): CodeInsetDto[] | Thenable => { + return this._proxy.$provideCodeInsets(handle, model.uri, token).then(dto => { + if (dto) { dto.forEach(obj => this._heapService.trackObject(obj)); } + return dto; + }); + }, + resolveCodeInset: (model: ITextModel, codeInset: CodeInsetDto, token: CancellationToken): CodeInsetDto | Thenable => { + return this._proxy.$resolveCodeInset(handle, model.uri, codeInset, token).then(obj => { + this._heapService.trackObject(obj); + return obj; + }); + } + }; + + if (typeof eventHandle === 'number') { + const emitter = new Emitter(); + this._registrations[eventHandle] = emitter; + provider.onDidChange = emitter.event; + } + + const langSelector = selector; + this._registrations[handle] = codeInset.CodeInsetProviderRegistry.register(langSelector, provider); + } + // --- declaration $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void { @@ -235,19 +275,13 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha $registerQuickFixSupport(handle: number, selector: ISerializedDocumentFilter[], providedCodeActionKinds?: string[]): void { this._registrations[handle] = modes.CodeActionProviderRegistry.register(selector, { - provideCodeActions: async (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise => { - const listDto = await this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token); - if (!listDto) { - return undefined; - } - return { - actions: MainThreadLanguageFeatures._reviveCodeActionDto(listDto.actions), - dispose: () => { - if (typeof listDto.cacheId === 'number') { - this._proxy.$releaseCodeActions(handle, listDto.cacheId); - } + provideCodeActions: (model: ITextModel, rangeOrSelection: EditorRange | Selection, context: modes.CodeActionContext, token: CancellationToken): Promise => { + return this._proxy.$provideCodeActions(handle, model.uri, rangeOrSelection, context, token).then(dto => { + if (dto) { + dto.forEach(obj => { this._heapService.trackObject(obj.command); }); } - }; + return MainThreadLanguageFeatures._reviveCodeActionDto(dto); + }); }, providedCodeActionKinds }); diff --git a/src/vs/workbench/api/browser/mainThreadMessageService.ts b/src/vs/workbench/api/browser/mainThreadMessageService.ts index 414d1b21d6..9a7873560c 100644 --- a/src/vs/workbench/api/browser/mainThreadMessageService.ts +++ b/src/vs/workbench/api/browser/mainThreadMessageService.ts @@ -90,8 +90,7 @@ export class MainThreadMessageService implements MainThreadMessageServiceShape { // if promise has not been resolved yet, now is the time to ensure a return value // otherwise if already resolved it means the user clicked one of the buttons Event.once(messageHandle.onDidClose)(() => { - dispose(primaryActions); - dispose(secondaryActions); + dispose(...primaryActions, ...secondaryActions); resolve(undefined); }); }); diff --git a/src/vs/workbench/api/browser/mainThreadProgress.ts b/src/vs/workbench/api/browser/mainThreadProgress.ts index f84e42ed8b..227ce760de 100644 --- a/src/vs/workbench/api/browser/mainThreadProgress.ts +++ b/src/vs/workbench/api/browser/mainThreadProgress.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IProgress, IProgressService, IProgressStep, ProgressLocation, IProgressOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress'; +import { IProgress, IProgressService2, IProgressStep, ProgressLocation, IProgressOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress'; import { MainThreadProgressShape, MainContext, IExtHostContext, ExtHostProgressShape, ExtHostContext } from '../common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { Action } from 'vs/base/common/actions'; @@ -22,13 +22,13 @@ class ManageExtensionAction extends Action { @extHostNamedCustomer(MainContext.MainThreadProgress) export class MainThreadProgress implements MainThreadProgressShape { - private readonly _progressService: IProgressService; + private readonly _progressService: IProgressService2; private _progress = new Map void, progress: IProgress }>(); private readonly _proxy: ExtHostProgressShape; constructor( extHostContext: IExtHostContext, - @IProgressService progressService: IProgressService, + @IProgressService2 progressService: IProgressService2, @ICommandService private readonly _commandService: ICommandService ) { this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostProgress); diff --git a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts index 17522b6ad6..599e294b9f 100644 --- a/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts +++ b/src/vs/workbench/api/browser/mainThreadSaveParticipant.ts @@ -28,7 +28,7 @@ import { ICommandService } from 'vs/platform/commands/common/commands'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; import { extHostCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { TextFileEditorModel } from 'vs/workbench/services/textfile/common/textFileEditorModel'; // {{SQL CARBON EDIT}} @@ -299,10 +299,10 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { if (CodeActionKind.SourceFixAll.contains(b)) { return 0; } - return -1; + return 1; } if (CodeActionKind.SourceFixAll.contains(b)) { - return 1; + return -1; } return 0; }); @@ -334,8 +334,6 @@ class CodeActionOnSaveParticipant implements ISaveParticipant { await this.applyCodeActions(actionsToRun.actions); } catch { // Failure to apply a code action should not block other on save actions - } finally { - actionsToRun.dispose(); } } } @@ -393,7 +391,7 @@ export class SaveParticipant implements ISaveParticipant { constructor( extHostContext: IExtHostContext, @IInstantiationService instantiationService: IInstantiationService, - @IProgressService private readonly _progressService: IProgressService, + @IProgressService2 private readonly _progressService: IProgressService2, @ILogService private readonly _logService: ILogService ) { this._saveParticipants = new IdleValue(() => [ diff --git a/src/vs/workbench/api/browser/mainThreadStatusBar.ts b/src/vs/workbench/api/browser/mainThreadStatusBar.ts index 317b6777a0..167fb9e5dd 100644 --- a/src/vs/workbench/api/browser/mainThreadStatusBar.ts +++ b/src/vs/workbench/api/browser/mainThreadStatusBar.ts @@ -3,10 +3,11 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol'; import { ThemeColor } from 'vs/platform/theme/common/themeService'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { dispose } from 'vs/base/common/lifecycle'; @extHostNamedCustomer(MainContext.MainThreadStatusBar) @@ -24,8 +25,8 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { this.entries.clear(); } - $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { - const entry: IStatusbarEntry = { text, tooltip, command, color }; + $setEntry(id: number, extensionId: ExtensionIdentifier, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: MainThreadStatusBarAlignment, priority: number): void { + const entry = { text, tooltip, command, color, extensionId }; // Reset existing entry if alignment or priority changed let existingEntry = this.entries.get(id); @@ -37,7 +38,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape { // Create new entry if not existing if (!existingEntry) { - this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, statusId, statusName, alignment, priority), alignment, priority }); + this.entries.set(id, { accessor: this.statusbarService.addEntry(entry, alignment, priority), alignment, priority }); } // Otherwise update diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 53460d3e2d..67cbc1549c 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -62,7 +62,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape // when the extension host process goes down ? } - public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }> { + public $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }> { const shellLaunchConfig: IShellLaunchConfig = { name, executable: shellPath, @@ -71,8 +71,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape waitOnExit, ignoreConfigurationCwd: true, env, - strictEnv, - runInBackground + strictEnv }; const terminal = this.terminalService.createTerminal(shellLaunchConfig); return Promise.resolve({ diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index e31cb5f668..4f4b7e64d0 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -13,6 +13,7 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ILabelService } from 'vs/platform/label/common/label'; import { IFileMatch, IPatternInfo, ISearchProgressItem, ISearchService } from 'vs/workbench/services/search/common/search'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; @@ -23,7 +24,6 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, MainThreadWorkspaceShape, IWorkspaceData, ITextSearchComplete } from '../common/extHost.protocol'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isEqualOrParent } from 'vs/base/common/resources'; -import { INotificationService } from 'vs/platform/notification/common/notification'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -39,7 +39,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @ITextFileService private readonly _textFileService: ITextFileService, @IWorkspaceEditingService private readonly _workspaceEditingService: IWorkspaceEditingService, - @INotificationService private readonly _notificationService: INotificationService, + @IStatusbarService private readonly _statusbarService: IStatusbarService, @IWindowService private readonly _windowService: IWindowService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @ILabelService private readonly _labelService: ILabelService, @@ -66,7 +66,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { const workspaceFoldersToAdd = foldersToAdd.map(f => ({ uri: URI.revive(f.uri), name: f.name })); // Indicate in status message - this._notificationService.status(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), { hideAfter: 10 * 1000 /* 10s */ }); + this._statusbarService.setStatusMessage(this.getStatusMessage(extensionName, workspaceFoldersToAdd.length, deleteCount), 10 * 1000 /* 10s */); return this._workspaceEditingService.updateFolders(index, deleteCount, workspaceFoldersToAdd, true); } diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index 8ae0ad29db..91547b6982 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -42,6 +42,7 @@ import { SaveReason } from 'vs/workbench/services/textfile/common/textfiles'; import { IMarkdownString } from 'vs/base/common/htmlContent'; import { ResolvedAuthority, RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset'; import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { IRelativePattern } from 'vs/base/common/glob'; import { IRemoteConsoleLog } from 'vs/base/common/console'; @@ -139,7 +140,7 @@ export interface MainThreadCommentsShape extends IDisposable { $registerCommentController(handle: number, id: string, label: string): void; $unregisterCommentController(handle: number): void; $updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void; - $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, extensionId: ExtensionIdentifier): modes.CommentThread2 | undefined; + $createCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange): modes.CommentThread2 | undefined; $updateCommentThread(handle: number, commentThreadHandle: number, threadId: string, resource: UriComponents, range: IRange, label: string, contextValue: string | undefined, comments: modes.Comment[], acceptInputCommand: modes.Command | undefined, additionalCommands: modes.Command[], deleteCommand: modes.Command | undefined, collapseState: modes.CommentThreadCollapsibleState): void; $deleteCommentThread(handle: number, commentThreadHandle: number): void; $setInputValue(handle: number, input: string): void; @@ -335,6 +336,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable { $unregister(handle: number): void; $registerDocumentSymbolProvider(handle: number, selector: ISerializedDocumentFilter[], label: string): void; $registerCodeLensSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void; + $registerCodeInsetSupport(handle: number, selector: ISerializedDocumentFilter[], eventHandle: number | undefined): void; $emitCodeLensEvent(eventHandle: number, event?: any): void; $registerDefinitionSupport(handle: number, selector: ISerializedDocumentFilter[]): void; $registerDeclarationSupport(handle: number, selector: ISerializedDocumentFilter[]): void; @@ -391,7 +393,7 @@ export interface MainThreadProgressShape extends IDisposable { } export interface MainThreadTerminalServiceShape extends IDisposable { - $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean, runInBackground?: boolean): Promise<{ id: number, name: string }>; + $createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string, cwd?: string | UriComponents, env?: { [key: string]: string | null }, waitOnExit?: boolean, strictEnv?: boolean): Promise<{ id: number, name: string }>; $createTerminalRenderer(name: string): Promise; $dispose(terminalId: number): void; $hide(terminalId: number): void; @@ -498,7 +500,7 @@ export interface MainThreadQuickOpenShape extends IDisposable { } export interface MainThreadStatusBarShape extends IDisposable { - $setEntry(id: number, statusId: string, statusName: string, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void; + $setEntry(id: number, extensionId: ExtensionIdentifier | undefined, text: string, tooltip: string, command: string, color: string | ThemeColor, alignment: statusbar.StatusbarAlignment, priority: number | undefined): void; $dispose(id: number): void; } @@ -511,22 +513,10 @@ export interface MainThreadTelemetryShape extends IDisposable { $publicLog(eventName: string, data?: any): void; } -export interface MainThreadEditorInsetsShape extends IDisposable { - $createEditorInset(handle: number, editorId: string, document: UriComponents, range: IRange, options: modes.IWebviewOptions): Promise; - $disposeEditorInset(handle: number): void; - - $setHtml(handle: number, value: string): void; - $setOptions(handle: number, options: modes.IWebviewOptions): void; - $postMessage(handle: number, value: any): Promise; -} - -export interface ExtHostEditorInsetsShape { - $onDidDispose(handle: number): void; - $onDidReceiveMessage(handle: number, message: any): void; -} - export type WebviewPanelHandle = string; +export type WebviewInsetHandle = number; + export interface WebviewPanelShowOptions { readonly viewColumn?: EditorViewColumn; readonly preserveFocus?: boolean; @@ -534,14 +524,15 @@ export interface WebviewPanelShowOptions { export interface MainThreadWebviewsShape extends IDisposable { $createWebviewPanel(handle: WebviewPanelHandle, viewType: string, title: string, showOptions: WebviewPanelShowOptions, options: modes.IWebviewPanelOptions & modes.IWebviewOptions, extensionId: ExtensionIdentifier, extensionLocation: UriComponents): void; + $createWebviewCodeInset(handle: WebviewInsetHandle, symbolId: string, options: modes.IWebviewOptions, extensionId: ExtensionIdentifier | undefined, extensionLocation: UriComponents | undefined): void; $disposeWebview(handle: WebviewPanelHandle): void; $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void; $setTitle(handle: WebviewPanelHandle, value: string): void; $setIconPath(handle: WebviewPanelHandle, value: { light: UriComponents, dark: UriComponents } | undefined): void; - $setHtml(handle: WebviewPanelHandle, value: string): void; - $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void; - $postMessage(handle: WebviewPanelHandle, value: any): Promise; + $setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void; + $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: modes.IWebviewOptions): void; + $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, value: any): Promise; $registerSerializer(viewType: string): void; $unregisterSerializer(viewType: string): void; @@ -997,11 +988,6 @@ export interface CodeActionDto { isPreferred?: boolean; } -export interface CodeActionListDto { - cacheId: number; - actions: ReadonlyArray; -} - export type CacheId = number; export type ChainedCacheId = [CacheId, CacheId]; @@ -1014,20 +1000,16 @@ export interface LinkDto { cacheId?: ChainedCacheId; range: IRange; url?: string | UriComponents; - tooltip?: string; } -export interface CodeLensListDto { - cacheId?: number; - lenses: CodeLensDto[]; -} - -export interface CodeLensDto { - cacheId?: ChainedCacheId; +export interface CodeLensDto extends ObjectIdentifier { range: IRange; + id?: string; command?: CommandDto; } +export type CodeInsetDto = ObjectIdentifier & codeInset.ICodeInsetSymbol; + export interface CallHierarchyDto { _id: number; kind: modes.SymbolKind; @@ -1040,9 +1022,10 @@ export interface CallHierarchyDto { export interface ExtHostLanguageFeaturesShape { $provideDocumentSymbols(handle: number, resource: UriComponents, token: CancellationToken): Promise; - $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise; + $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise; $resolveCodeLens(handle: number, symbol: CodeLensDto, token: CancellationToken): Promise; - $releaseCodeLenses(handle: number, id: number): void; + $provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise; + $resolveCodeInset(handle: number, resource: UriComponents, symbol: CodeInsetDto, token: CancellationToken): Promise; $provideDefinition(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideDeclaration(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideImplementation(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; @@ -1050,8 +1033,7 @@ export interface ExtHostLanguageFeaturesShape { $provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise; $provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise; - $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise; - $releaseCodeActions(handle: number, cacheId: number): void; + $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise; $provideDocumentFormattingEdits(handle: number, resource: UriComponents, options: modes.FormattingOptions, token: CancellationToken): Promise; $provideDocumentRangeFormattingEdits(handle: number, resource: UriComponents, range: IRange, options: modes.FormattingOptions, token: CancellationToken): Promise; $provideOnTypeFormattingEdits(handle: number, resource: UriComponents, position: IPosition, ch: string, options: modes.FormattingOptions, token: CancellationToken): Promise; @@ -1230,7 +1212,6 @@ export interface ExtHostCommentsShape { $provideDocumentComments(handle: number, document: UriComponents): Promise; $createNewCommentThread(handle: number, document: UriComponents, range: IRange, text: string): Promise; $createCommentThreadTemplate(commentControllerHandle: number, uriComponents: UriComponents, range: IRange): void; - $updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange): Promise; $onCommentWidgetInputChange(commentControllerHandle: number, document: UriComponents, range: IRange, input: string | undefined): Promise; $deleteCommentThread(commentControllerHandle: number, commentThreadHandle: number): void; $provideCommentingRanges(commentControllerHandle: number, uriComponents: UriComponents, token: CancellationToken): Promise; @@ -1268,7 +1249,6 @@ export const MainContext = { MainThreadDocuments: createMainId('MainThreadDocuments'), MainThreadDocumentContentProviders: createMainId('MainThreadDocumentContentProviders'), MainThreadTextEditors: createMainId('MainThreadTextEditors'), - MainThreadEditorInsets: createMainId('MainThreadEditorInsets'), MainThreadErrors: createMainId('MainThreadErrors'), MainThreadTreeViews: createMainId('MainThreadTreeViews'), MainThreadKeytar: createMainId('MainThreadKeytar'), @@ -1319,7 +1299,6 @@ export const ExtHostContext = { ExtHostWorkspace: createExtId('ExtHostWorkspace'), ExtHostWindow: createExtId('ExtHostWindow'), ExtHostWebviews: createExtId('ExtHostWebviews'), - ExtHostEditorInsets: createExtId('ExtHostEditorInsets'), ExtHostProgress: createMainId('ExtHostProgress'), ExtHostComments: createMainId('ExtHostComments'), ExtHostStorage: createMainId('ExtHostStorage'), diff --git a/src/vs/workbench/api/common/extHostApiCommands.ts b/src/vs/workbench/api/common/extHostApiCommands.ts index 14826c7f5d..2c85b26e86 100644 --- a/src/vs/workbench/api/common/extHostApiCommands.ts +++ b/src/vs/workbench/api/common/extHostApiCommands.ts @@ -504,7 +504,7 @@ export class ExtHostApiCommands { private _executeCodeLensProvider(resource: URI, itemResolveCount: number): Promise { const args = { resource, itemResolveCount }; - return this._commands.executeCommand('_executeCodeLensProvider', args) + return this._commands.executeCommand('_executeCodeLensProvider', args) .then(tryMapWith(item => { return new types.CodeLens( typeConverters.Range.to(item.range), diff --git a/src/vs/workbench/api/common/extHostCodeInsets.ts b/src/vs/workbench/api/common/extHostCodeInsets.ts deleted file mode 100644 index 7fdfdbe348..0000000000 --- a/src/vs/workbench/api/common/extHostCodeInsets.ts +++ /dev/null @@ -1,130 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Emitter } from 'vs/base/common/event'; -import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; -import * as vscode from 'vscode'; -import { MainThreadEditorInsetsShape } from './extHost.protocol'; -import { ExtHostEditors } from 'vs/workbench/api/common/extHostTextEditors'; -import { DisposableStore } from 'vs/base/common/lifecycle'; -import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor'; - -export class ExtHostEditorInsets implements ExtHostEditorInsets { - - private _handlePool = 0; - private _disposables = new DisposableStore(); - private _insets = new Map }>(); - - constructor( - private readonly _proxy: MainThreadEditorInsetsShape, - private readonly _editors: ExtHostEditors - ) { - - // dispose editor inset whenever the hosting editor goes away - this._disposables.add(_editors.onDidChangeVisibleTextEditors(() => { - const visibleEditor = _editors.getVisibleTextEditors(); - this._insets.forEach(value => { - if (visibleEditor.indexOf(value.editor) < 0) { - value.inset.dispose(); // will remove from `this._insets` - } - }); - })); - } - - dispose(): void { - this._insets.forEach(value => value.inset.dispose()); - this._disposables.dispose(); - } - - createWebviewEditorInset(editor: vscode.TextEditor, range: vscode.Range, options?: vscode.WebviewOptions): vscode.WebviewEditorInset { - - let apiEditor: ExtHostTextEditor | undefined; - for (const candidate of this._editors.getVisibleTextEditors()) { - if (candidate === editor) { - apiEditor = candidate; - break; - } - } - if (!apiEditor) { - throw new Error('not a visible editor'); - } - - const that = this; - const handle = this._handlePool++; - const onDidReceiveMessage = new Emitter(); - const onDidDispose = new Emitter(); - - const webview = new class implements vscode.Webview { - - private _html: string = ''; - private _options: vscode.WebviewOptions; - - set options(value: vscode.WebviewOptions) { - this._options = value; - that._proxy.$setOptions(handle, value); - } - - get options(): vscode.WebviewOptions { - return this._options; - } - - set html(value: string) { - this._html = value; - that._proxy.$setHtml(handle, value); - } - - get html(): string { - return this._html; - } - - get onDidReceiveMessage(): vscode.Event { - return onDidReceiveMessage.event; - } - - postMessage(message: any): Thenable { - return that._proxy.$postMessage(handle, message); - } - }; - - const inset = new class implements vscode.WebviewEditorInset { - - readonly editor: vscode.TextEditor = editor; - readonly range: vscode.Range = range; - readonly webview: vscode.Webview = webview; - readonly onDidDispose: vscode.Event = onDidDispose.event; - - dispose(): void { - if (that._insets.has(handle)) { - that._insets.delete(handle); - that._proxy.$disposeEditorInset(handle); - onDidDispose.fire(); - - // final cleanup - onDidDispose.dispose(); - onDidReceiveMessage.dispose(); - } - } - }; - - this._proxy.$createEditorInset(handle, apiEditor.id, apiEditor.document.uri, typeConverters.Range.from(range), options || {}); - this._insets.set(handle, { editor, inset, onDidReceiveMessage }); - - return inset; - } - - $onDidDispose(handle: number): void { - const value = this._insets.get(handle); - if (value) { - value.inset.dispose(); - } - } - - $onDidReceiveMessage(handle: number, message: any): void { - const value = this._insets.get(handle); - if (value) { - value.onDidReceiveMessage.fire(message); - } - } -} diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index a7fbe73c74..a5c2f0f738 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -18,7 +18,6 @@ import { revive } from 'vs/base/common/marshalling'; import { Range } from 'vs/editor/common/core/range'; import { Position } from 'vs/editor/common/core/position'; import { URI } from 'vs/base/common/uri'; -import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; interface CommandHandler { callback: Function; @@ -212,35 +211,6 @@ export class CommandsConverter { this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this); } - toInternal2(command: vscode.Command | undefined, disposables: DisposableStore): CommandDto | undefined { - - if (!command) { - return undefined; - } - - const result: CommandDto = { - $ident: undefined, - id: command.command, - title: command.title, - tooltip: command.tooltip - }; - - if (command.command && isNonEmptyArray(command.arguments)) { - // we have a contributed command with arguments. that - // means we don't want to send the arguments around - - const id = this._heap.keep(command); - disposables.add(toDisposable(() => this._heap.delete(id))); - result.$ident = id; - - result.id = this._delegatingCommandId; - result.arguments = [id]; - - } - - return result; - } - toInternal(command: vscode.Command): CommandDto; toInternal(command: undefined): undefined; toInternal(command: vscode.Command | undefined): CommandDto | undefined; diff --git a/src/vs/workbench/api/common/extHostComments.ts b/src/vs/workbench/api/common/extHostComments.ts index fcb82cc10c..67e6e3c4fd 100644 --- a/src/vs/workbench/api/common/extHostComments.ts +++ b/src/vs/workbench/api/common/extHostComments.ts @@ -162,16 +162,6 @@ export class ExtHostComments implements ExtHostCommentsShape { commentController.$createCommentThreadTemplate(uriComponents, range); } - async $updateCommentThreadTemplate(commentControllerHandle: number, threadHandle: number, range: IRange) { - const commentController = this._commentControllers.get(commentControllerHandle); - - if (!commentController) { - return; - } - - commentController.$updateCommentThreadTemplate(threadHandle, range); - } - $onCommentWidgetInputChange(commentControllerHandle: number, uriComponents: UriComponents, range: IRange, input: string): Promise { const commentController = this._commentControllers.get(commentControllerHandle); @@ -592,8 +582,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { private _id: string | undefined, private _uri: vscode.Uri, private _range: vscode.Range, - private _comments: vscode.Comment[], - extensionId: ExtensionIdentifier + private _comments: vscode.Comment[] ) { if (this._id === undefined) { this._id = `${_commentController.id}.${this.handle}`; @@ -604,8 +593,7 @@ export class ExtHostCommentThread implements vscode.CommentThread { this.handle, this._id, this._uri, - extHostTypeConverter.Range.from(this._range), - extensionId + extHostTypeConverter.Range.from(this._range) ); this._localDisposables = []; @@ -753,7 +741,7 @@ class ExtHostCommentController implements vscode.CommentController { } constructor( - private _extension: IExtensionDescription, + _extension: IExtensionDescription, private _handle: number, private readonly _commandsConverter: CommandsConverter, private _proxy: MainThreadCommentsShape, @@ -767,30 +755,23 @@ class ExtHostCommentController implements vscode.CommentController { createCommentThread(id: string, resource: vscode.Uri, range: vscode.Range, comments: vscode.Comment[]): vscode.CommentThread; createCommentThread(arg0: vscode.Uri | string, arg1: vscode.Uri | vscode.Range, arg2: vscode.Range | vscode.Comment[], arg3?: vscode.Comment[]): vscode.CommentThread { if (typeof arg0 === 'string') { - const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[], this._extension.identifier); + const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, arg0, arg1 as vscode.Uri, arg2 as vscode.Range, arg3 as vscode.Comment[]); this._threads.set(commentThread.handle, commentThread); return commentThread; } else { - const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[], this._extension.identifier); + const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, arg0 as vscode.Uri, arg1 as vscode.Range, arg2 as vscode.Comment[]); this._threads.set(commentThread.handle, commentThread); return commentThread; } } $createCommentThreadTemplate(uriComponents: UriComponents, range: IRange) { - const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), [], this._extension.identifier); + const commentThread = new ExtHostCommentThread(this._proxy, this._commandsConverter, this, undefined, URI.revive(uriComponents), extHostTypeConverter.Range.to(range), []); commentThread.collapsibleState = modes.CommentThreadCollapsibleState.Expanded; this._threads.set(commentThread.handle, commentThread); return commentThread; } - $updateCommentThreadTemplate(threadHandle: number, range: IRange) { - let thread = this._threads.get(threadHandle); - if (thread) { - thread.range = extHostTypeConverter.Range.to(range); - } - } - $deleteCommentThread(threadHandle: number) { let thread = this._threads.get(threadHandle); diff --git a/src/vs/workbench/api/common/extHostLanguageFeatures.ts b/src/vs/workbench/api/common/extHostLanguageFeatures.ts index 41d6359bcc..a504b46245 100644 --- a/src/vs/workbench/api/common/extHostLanguageFeatures.ts +++ b/src/vs/workbench/api/common/extHostLanguageFeatures.ts @@ -15,7 +15,7 @@ import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments'; import { ExtHostCommands, CommandsConverter } from 'vs/workbench/api/common/extHostCommands'; import { ExtHostDiagnostics } from 'vs/workbench/api/common/extHostDiagnostics'; import { asPromise } from 'vs/base/common/async'; -import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, SuggestDataDto, LinksListDto, ChainedCacheId, CodeLensListDto, CodeActionListDto } from './extHost.protocol'; +import { MainContext, MainThreadLanguageFeaturesShape, ExtHostLanguageFeaturesShape, ObjectIdentifier, IRawColorInfo, IMainContext, IdObject, ISerializedRegExp, ISerializedIndentationRule, ISerializedOnEnterRule, ISerializedLanguageConfiguration, WorkspaceSymbolDto, SuggestResultDto, WorkspaceSymbolsDto, CodeActionDto, ISerializedDocumentFilter, WorkspaceEditDto, ISerializedSignatureHelpProviderMetadata, LinkDto, CodeLensDto, MainThreadWebviewsShape, CodeInsetDto, SuggestDataDto, LinksListDto, ChainedCacheId } from './extHost.protocol'; import { regExpLeadsToEndlessLoop, regExpFlags } from 'vs/base/common/strings'; import { IPosition } from 'vs/editor/common/core/position'; import { IRange, Range as EditorRange } from 'vs/editor/common/core/range'; @@ -25,10 +25,11 @@ import { ISelection, Selection } from 'vs/editor/common/core/selection'; import { ILogService } from 'vs/platform/log/common/log'; import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { ExtHostWebview } from 'vs/workbench/api/common/extHostWebview'; +import * as codeInset from 'vs/workbench/contrib/codeinset/common/codeInset'; +import { generateUuid } from 'vs/base/common/uuid'; import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; import { LRUCache } from 'vs/base/common/map'; -import { IURITransformer } from 'vs/base/common/uriIpc'; -import { DisposableStore, dispose } from 'vs/base/common/lifecycle'; // --- adapter @@ -103,48 +104,34 @@ class CodeLensAdapter { private static _badCmd: vscode.Command = { command: 'missing', title: '!!MISSING: command!!' }; - private readonly _cache = new Cache(); - private readonly _disposables = new Map(); - constructor( private readonly _documents: ExtHostDocuments, private readonly _commands: CommandsConverter, + private readonly _heapService: ExtHostHeapService, private readonly _provider: vscode.CodeLensProvider ) { } - provideCodeLenses(resource: URI, token: CancellationToken): Promise { + provideCodeLenses(resource: URI, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); return asPromise(() => this._provider.provideCodeLenses(doc, token)).then(lenses => { - - if (!lenses || token.isCancellationRequested) { - return undefined; + const result: CodeLensDto[] = []; + if (isNonEmptyArray(lenses)) { + for (const lens of lenses) { + const id = this._heapService.keep(lens); + result.push(ObjectIdentifier.mixin({ + range: typeConvert.Range.from(lens.range), + command: this._commands.toInternal(lens.command) + }, id)); + } } - - const cacheId = this._cache.add(lenses); - const disposables = new DisposableStore(); - this._disposables.set(cacheId, disposables); - - const result: CodeLensListDto = { - cacheId, - lenses: [], - }; - - for (let i = 0; i < lenses.length; i++) { - result.lenses.push({ - cacheId: [cacheId, i], - range: typeConvert.Range.from(lenses[i].range), - command: this._commands.toInternal2(lenses[i].command, disposables) - }); - } - return result; }); } resolveCodeLens(symbol: CodeLensDto, token: CancellationToken): Promise { - const lens = symbol.cacheId && this._cache.get(...symbol.cacheId); + const lens = this._heapService.get(ObjectIdentifier.of(symbol)); if (!lens) { return Promise.resolve(undefined); } @@ -157,26 +144,51 @@ class CodeLensAdapter { } return resolve.then(newLens => { - if (token.isCancellationRequested) { - return undefined; - } - - const disposables = symbol.cacheId && this._disposables.get(symbol.cacheId[0]); - if (!disposables) { - // We've already been disposed of - return undefined; - } - newLens = newLens || lens; - symbol.command = this._commands.toInternal2(newLens.command || CodeLensAdapter._badCmd, disposables); + symbol.command = this._commands.toInternal(newLens.command || CodeLensAdapter._badCmd); return symbol; }); } +} - releaseCodeLenses(cachedId: number): void { - dispose(this._disposables.get(cachedId)); - this._disposables.delete(cachedId); - this._cache.delete(cachedId); +class CodeInsetAdapter { + + constructor( + private readonly _documents: ExtHostDocuments, + private readonly _heapService: ExtHostHeapService, + private readonly _provider: vscode.CodeInsetProvider + ) { } + + provideCodeInsets(resource: URI, token: CancellationToken): Promise { + const doc = this._documents.getDocument(resource); + return asPromise(() => this._provider.provideCodeInsets(doc, token)).then(insets => { + if (Array.isArray(insets)) { + return insets.map(inset => { + const $ident = this._heapService.keep(inset); + const id = generateUuid(); + return { + $ident, + id, + range: typeConvert.Range.from(inset.range), + height: inset.height + }; + }); + } + return undefined; + }); + } + + resolveCodeInset(symbol: CodeInsetDto, webview: vscode.Webview, token: CancellationToken): Promise { + + const inset = this._heapService.get(ObjectIdentifier.of(symbol)); + if (!inset) { + return Promise.resolve(symbol); + } + + return asPromise(() => this._provider.resolveCodeInset(inset, webview, token)).then(newInset => { + newInset = newInset || inset; + return symbol; + }); } } @@ -316,9 +328,6 @@ export interface CustomCodeAction extends CodeActionDto { class CodeActionAdapter { private static readonly _maxCodeActionsPerFile: number = 1000; - private readonly _cache = new Cache(); - private readonly _disposables = new Map(); - constructor( private readonly _documents: ExtHostDocuments, private readonly _commands: CommandsConverter, @@ -328,7 +337,7 @@ class CodeActionAdapter { private readonly _extensionId: ExtensionIdentifier ) { } - provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + provideCodeActions(resource: URI, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { const doc = this._documents.getDocument(resource); const ran = Selection.isISelection(rangeOrSelection) @@ -351,39 +360,34 @@ class CodeActionAdapter { }; return asPromise(() => this._provider.provideCodeActions(doc, ran, codeActionContext, token)).then(commandsOrActions => { - if (!isNonEmptyArray(commandsOrActions) || token.isCancellationRequested) { + if (!isNonEmptyArray(commandsOrActions)) { return undefined; } - - const cacheId = this._cache.add(commandsOrActions); - const disposables = new DisposableStore(); - this._disposables.set(cacheId, disposables); - - const actions: CustomCodeAction[] = []; + const result: CustomCodeAction[] = []; for (const candidate of commandsOrActions) { if (!candidate) { continue; } if (CodeActionAdapter._isCommand(candidate)) { // old school: synthetic code action - actions.push({ + result.push({ _isSynthetic: true, title: candidate.title, - command: this._commands.toInternal2(candidate, disposables), + command: this._commands.toInternal(candidate), }); } else { if (codeActionContext.only) { if (!candidate.kind) { this._logService.warn(`${this._extensionId.value} - Code actions of kind '${codeActionContext.only.value} 'requested but returned code action does not have a 'kind'. Code action will be dropped. Please set 'CodeAction.kind'.`); } else if (!codeActionContext.only.contains(candidate.kind)) { - this._logService.warn(`${this._extensionId.value} - Code actions of kind '${codeActionContext.only.value} 'requested but returned code action is of kind '${candidate.kind.value}'. Code action will be dropped. Please check 'CodeActionContext.only' to only return requested code actions.`); + this._logService.warn(`${this._extensionId.value} -Code actions of kind '${codeActionContext.only.value} 'requested but returned code action is of kind '${candidate.kind.value}'. Code action will be dropped. Please check 'CodeActionContext.only' to only return requested code actions.`); } } // new school: convert code action - actions.push({ + result.push({ title: candidate.title, - command: candidate.command && this._commands.toInternal2(candidate.command, disposables), + command: candidate.command && this._commands.toInternal(candidate.command), diagnostics: candidate.diagnostics && candidate.diagnostics.map(typeConvert.Diagnostic.from), edit: candidate.edit && typeConvert.WorkspaceEdit.from(candidate.edit), kind: candidate.kind && candidate.kind.value, @@ -392,16 +396,10 @@ class CodeActionAdapter { } } - return { cacheId, actions }; + return result; }); } - public releaseCodeActions(cachedId: number): void { - dispose(this._disposables.get(cachedId)); - this._disposables.delete(cachedId); - this._cache.delete(cachedId); - } - private static _isCommand(thing: any): thing is vscode.Command { return typeof (thing).command === 'string' && typeof (thing).title === 'string'; } @@ -626,7 +624,6 @@ class SuggestAdapter { private _provider: vscode.CompletionItemProvider; private _cache = new Cache(); - private _disposables = new Map(); constructor(documents: ExtHostDocuments, commands: CommandsConverter, provider: vscode.CompletionItemProvider) { this._documents = documents; @@ -646,18 +643,13 @@ class SuggestAdapter { return undefined; } - if (token.isCancellationRequested) { - // cancelled -> return without further ado, esp no caching - // of results as they will leak - return undefined; - } - - const list = Array.isArray(value) ? new CompletionList(value) : value; + let list = Array.isArray(value) ? new CompletionList(value) : value; + let pid: number | undefined; // keep result for providers that support resolving - const pid: number = SuggestAdapter.supportsResolving(this._provider) ? this._cache.add(list.items) : this._cache.add([]); - const disposables = new DisposableStore(); - this._disposables.set(pid, disposables); + if (SuggestAdapter.supportsResolving(this._provider)) { + pid = this._cache.add(list.items); + } // the default text edit range const wordRangeBeforePos = (doc.getWordRangeAtPosition(pos) as Range || new Range(pos, pos)) @@ -671,7 +663,7 @@ class SuggestAdapter { }; for (let i = 0; i < list.items.length; i++) { - const suggestion = this._convertCompletionItem(list.items[i], pos, [pid, i]); + const suggestion = this._convertCompletionItem(list.items[i], pos, pid && [pid, i] || undefined); // check for bad completion item // for the converter did warn if (suggestion) { @@ -706,22 +698,15 @@ class SuggestAdapter { } releaseCompletionItems(id: number): any { - dispose(this._disposables.get(id)); - this._disposables.delete(id); this._cache.delete(id); } - private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId): SuggestDataDto | undefined { + private _convertCompletionItem(item: vscode.CompletionItem, position: vscode.Position, id: ChainedCacheId | undefined): SuggestDataDto | undefined { if (typeof item.label !== 'string' || item.label.length === 0) { console.warn('INVALID text edit -> must have at least a label'); return undefined; } - const disposables = this._disposables.get(id[0]); - if (!disposables) { - throw Error('DisposableStore is missing...'); - } - const result: SuggestDataDto = { // x: id, @@ -736,7 +721,7 @@ class SuggestAdapter { i: item.keepWhitespace ? modes.CompletionItemInsertTextRule.KeepWhitespace : 0, k: item.commitCharacters, l: item.additionalTextEdits && item.additionalTextEdits.map(typeConvert.TextEdit.from), - m: this._commands.toInternal2(item.command, disposables), + m: this._commands.toInternal(item.command), }; // 'insertText'-logic @@ -846,12 +831,6 @@ class LinkProviderAdapter { return undefined; } - if (token.isCancellationRequested) { - // cancelled -> return without further ado, esp no caching - // of results as they will leak - return undefined; - } - if (typeof this._provider.resolveDocumentLink !== 'function') { // no resolve -> no caching return { links: links.map(typeConvert.DocumentLink.from) }; @@ -1048,7 +1027,7 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov | DocumentHighlightAdapter | ReferenceAdapter | CodeActionAdapter | DocumentFormattingAdapter | RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter | SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter | TypeDefinitionAdapter - | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter; + | ColorProviderAdapter | FoldingProviderAdapter | CodeInsetAdapter | DeclarationAdapter | SelectionRangeAdapter | CallHierarchyAdapter; class AdapterData { constructor( @@ -1057,11 +1036,15 @@ class AdapterData { ) { } } +export interface ISchemeTransformer { + transformOutgoing(scheme: string): string; +} + export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private static _handlePool: number = 0; - private readonly _uriTransformer: IURITransformer | null; + private readonly _schemeTransformer: ISchemeTransformer | null; private _proxy: MainThreadLanguageFeaturesShape; private _documents: ExtHostDocuments; private _commands: ExtHostCommands; @@ -1069,23 +1052,25 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { private _diagnostics: ExtHostDiagnostics; private _adapter = new Map(); private readonly _logService: ILogService; + private _webviewProxy: MainThreadWebviewsShape; constructor( mainContext: IMainContext, - uriTransformer: IURITransformer | null, + schemeTransformer: ISchemeTransformer | null, documents: ExtHostDocuments, commands: ExtHostCommands, heapMonitor: ExtHostHeapService, diagnostics: ExtHostDiagnostics, logService: ILogService ) { - this._uriTransformer = uriTransformer; + this._schemeTransformer = schemeTransformer; this._proxy = mainContext.getProxy(MainContext.MainThreadLanguageFeatures); this._documents = documents; this._commands = commands; this._heapService = heapMonitor; this._diagnostics = diagnostics; this._logService = logService; + this._webviewProxy = mainContext.getProxy(MainContext.MainThreadWebviews); } private _transformDocumentSelector(selector: vscode.DocumentSelector): Array { @@ -1114,8 +1099,8 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { } private _transformScheme(scheme: string | undefined): string | undefined { - if (this._uriTransformer && typeof scheme === 'string') { - return this._uriTransformer.transformOutgoingScheme(scheme); + if (this._schemeTransformer && typeof scheme === 'string') { + return this._schemeTransformer.transformOutgoing(scheme); } return scheme; } @@ -1188,7 +1173,7 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { const handle = this._nextHandle(); const eventHandle = typeof provider.onDidChangeCodeLenses === 'function' ? this._nextHandle() : undefined; - this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, provider), extension)); + this._adapter.set(handle, new AdapterData(new CodeLensAdapter(this._documents, this._commands.converter, this._heapService, provider), extension)); this._proxy.$registerCodeLensSupport(handle, this._transformDocumentSelector(selector), eventHandle); let result = this._createDisposable(handle); @@ -1200,16 +1185,43 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { return result; } - $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise { - return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), undefined); + $provideCodeLenses(handle: number, resource: UriComponents, token: CancellationToken): Promise { + return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.provideCodeLenses(URI.revive(resource), token), []); } - $resolveCodeLens(handle: number, symbol: CodeLensDto, token: CancellationToken): Promise { + $resolveCodeLens(handle: number, symbol: modes.ICodeLensSymbol, token: CancellationToken): Promise { return this._withAdapter(handle, CodeLensAdapter, adapter => adapter.resolveCodeLens(symbol, token), undefined); } - $releaseCodeLenses(handle: number, cacheId: number): void { - this._withAdapter(handle, CodeLensAdapter, adapter => Promise.resolve(adapter.releaseCodeLenses(cacheId)), undefined); + // --- code insets + + registerCodeInsetProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable { + const handle = this._nextHandle(); + const eventHandle = typeof provider.onDidChangeCodeInsets === 'function' ? this._nextHandle() : undefined; + + this._adapter.set(handle, new AdapterData(new CodeInsetAdapter(this._documents, this._heapService, provider), extension)); + this._proxy.$registerCodeInsetSupport(handle, this._transformDocumentSelector(selector), eventHandle); + let result = this._createDisposable(handle); + + if (eventHandle !== undefined && provider.onDidChangeCodeInsets) { + const subscription = provider.onDidChangeCodeInsets(_ => this._proxy.$emitCodeLensEvent(eventHandle)); + result = Disposable.from(result, subscription); + } + + return result; + } + + $provideCodeInsets(handle: number, resource: UriComponents, token: CancellationToken): Promise { + return this._withAdapter(handle, CodeInsetAdapter, adapter => adapter.provideCodeInsets(URI.revive(resource), token), undefined); + } + + $resolveCodeInset(handle: number, _resource: UriComponents, symbol: codeInset.ICodeInsetSymbol, token: CancellationToken): Promise { + const webviewHandle = Math.random(); + const webview = new ExtHostWebview(webviewHandle, this._webviewProxy, { enableScripts: true }); + return this._withAdapter(handle, CodeInsetAdapter, async (adapter, extension) => { + await this._webviewProxy.$createWebviewCodeInset(webviewHandle, symbol.id, { enableCommandUris: true, enableScripts: true }, extension ? extension.identifier : undefined, extension ? extension.extensionLocation : undefined); + return adapter.resolveCodeInset(symbol, webview, token); + }, symbol); } // --- declaration @@ -1299,14 +1311,10 @@ export class ExtHostLanguageFeatures implements ExtHostLanguageFeaturesShape { } - $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { + $provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise { return this._withAdapter(handle, CodeActionAdapter, adapter => adapter.provideCodeActions(URI.revive(resource), rangeOrSelection, context, token), undefined); } - $releaseCodeActions(handle: number, cacheId: number): void { - this._withAdapter(handle, CodeActionAdapter, adapter => Promise.resolve(adapter.releaseCodeActions(cacheId)), undefined); - } - // --- formatting registerDocumentFormattingEditProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.DocumentFormattingEditProvider): vscode.Disposable { diff --git a/src/vs/workbench/api/common/extHostStatusBar.ts b/src/vs/workbench/api/common/extHostStatusBar.ts index 08632864fd..547b6c0886 100644 --- a/src/vs/workbench/api/common/extHostStatusBar.ts +++ b/src/vs/workbench/api/common/extHostStatusBar.ts @@ -7,7 +7,7 @@ import { StatusbarAlignment as MainThreadStatusBarAlignment } from 'vs/platform/ import { StatusBarAlignment as ExtHostStatusBarAlignment, Disposable, ThemeColor } from './extHostTypes'; import { StatusBarItem, StatusBarAlignment } from 'vscode'; import { MainContext, MainThreadStatusBarShape, IMainContext } from './extHost.protocol'; -import { localize } from 'vs/nls'; +import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; export class ExtHostStatusBarEntry implements StatusBarItem { private static ID_GEN = 0; @@ -18,9 +18,6 @@ export class ExtHostStatusBarEntry implements StatusBarItem { private _disposed: boolean; private _visible: boolean; - private _statusId: string; - private _statusName: string; - private _text: string; private _tooltip: string; private _color: string | ThemeColor; @@ -29,13 +26,14 @@ export class ExtHostStatusBarEntry implements StatusBarItem { private _timeoutHandle: any; private _proxy: MainThreadStatusBarShape; - constructor(proxy: MainThreadStatusBarShape, id: string, name: string, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) { + private _extensionId?: ExtensionIdentifier; + + constructor(proxy: MainThreadStatusBarShape, extensionId: ExtensionIdentifier | undefined, alignment: ExtHostStatusBarAlignment = ExtHostStatusBarAlignment.Left, priority?: number) { this._id = ExtHostStatusBarEntry.ID_GEN++; this._proxy = proxy; - this._statusId = id; - this._statusName = name; this._alignment = alignment; this._priority = priority; + this._extensionId = extensionId; } public get id(): number { @@ -109,7 +107,7 @@ export class ExtHostStatusBarEntry implements StatusBarItem { this._timeoutHandle = undefined; // Set to status bar - this._proxy.$setEntry(this.id, this._statusId, this._statusName, this.text, this.tooltip, this.command, this.color, + this._proxy.$setEntry(this.id, this._extensionId, this.text, this.tooltip, this.command, this.color, this._alignment === ExtHostStatusBarAlignment.Left ? MainThreadStatusBarAlignment.LEFT : MainThreadStatusBarAlignment.RIGHT, this._priority); }, 0); @@ -127,7 +125,7 @@ class StatusBarMessage { private _messages: { message: string }[] = []; constructor(statusBar: ExtHostStatusBar) { - this._item = statusBar.createStatusBarEntry('status.extensionMessage', localize('status.extensionMessage', "Extension Status"), ExtHostStatusBarAlignment.Left, Number.MIN_VALUE); + this._item = statusBar.createStatusBarEntry(undefined, ExtHostStatusBarAlignment.Left, Number.MIN_VALUE); } dispose() { @@ -169,8 +167,8 @@ export class ExtHostStatusBar { this._statusMessage = new StatusBarMessage(this); } - createStatusBarEntry(id: string, name: string, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem { - return new ExtHostStatusBarEntry(this._proxy, id, name, alignment, priority); + createStatusBarEntry(extensionId: ExtensionIdentifier | undefined, alignment?: ExtHostStatusBarAlignment, priority?: number): StatusBarItem { + return new ExtHostStatusBarEntry(this._proxy, extensionId, alignment, priority); } setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): Disposable { diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 692a774815..6e52f764b5 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -808,8 +808,7 @@ export namespace DocumentLink { export function from(link: vscode.DocumentLink): modes.ILink { return { range: Range.from(link.range), - url: link.target, - tooltip: link.tooltip + url: link.target }; } @@ -859,7 +858,10 @@ export namespace Color { export namespace SelectionRange { export function from(obj: vscode.SelectionRange): modes.SelectionRange { - return { range: Range.from(obj.range) }; + return { + kind: '', + range: Range.from(obj.range) + }; } export function to(obj: modes.SelectionRange): vscode.SelectionRange { diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index e41d7d50f9..1b9d8bab4e 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -1440,8 +1440,6 @@ export class DocumentLink { target?: URI; - tooltip?: string; - constructor(range: Range, target: URI | undefined) { if (target && !(target instanceof URI)) { throw illegalArgument('target'); diff --git a/src/vs/workbench/api/common/extHostWebview.ts b/src/vs/workbench/api/common/extHostWebview.ts index 21d51dc505..03d782deac 100644 --- a/src/vs/workbench/api/common/extHostWebview.ts +++ b/src/vs/workbench/api/common/extHostWebview.ts @@ -8,7 +8,7 @@ import { URI } from 'vs/base/common/uri'; import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters'; import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import * as vscode from 'vscode'; -import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState } from './extHost.protocol'; +import { ExtHostWebviewsShape, IMainContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelViewState, WebviewInsetHandle } from './extHost.protocol'; import { Disposable } from './extHostTypes'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import * as modes from 'vs/editor/common/modes'; @@ -16,7 +16,7 @@ import * as modes from 'vs/editor/common/modes'; type IconPath = URI | { light: URI, dark: URI }; export class ExtHostWebview implements vscode.Webview { - private readonly _handle: WebviewPanelHandle; + private readonly _handle: WebviewPanelHandle | WebviewInsetHandle; private readonly _proxy: MainThreadWebviewsShape; private _html: string; private _options: vscode.WebviewOptions; @@ -26,7 +26,7 @@ export class ExtHostWebview implements vscode.Webview { public readonly onDidReceiveMessage: Event = this._onMessageEmitter.event; constructor( - handle: WebviewPanelHandle, + handle: WebviewPanelHandle | WebviewInsetHandle, proxy: MainThreadWebviewsShape, options: vscode.WebviewOptions ) { diff --git a/src/vs/workbench/api/common/menusExtensionPoint.ts b/src/vs/workbench/api/common/menusExtensionPoint.ts index 80942178ae..9e6d686543 100644 --- a/src/vs/workbench/api/common/menusExtensionPoint.ts +++ b/src/vs/workbench/api/common/menusExtensionPoint.ts @@ -21,6 +21,7 @@ namespace schema { export interface IUserFriendlyMenuItem { command: string; alt?: string; + precondition?: string; when?: string; group?: string; } @@ -83,6 +84,10 @@ namespace schema { collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'alt')); return false; } + if (item.precondition && typeof item.precondition !== 'string') { + collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition')); + return false; + } if (item.when && typeof item.when !== 'string') { collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'when')); return false; @@ -107,6 +112,10 @@ namespace schema { description: localize('vscode.extension.contributes.menuItem.alt', 'Identifier of an alternative command to execute. The command must be declared in the \'commands\'-section'), type: 'string' }, + precondition: { + description: localize('vscode.extension.contributes.menuItem.precondition', 'Condition which must be true to enable this item'), + type: 'string' + }, when: { description: localize('vscode.extension.contributes.menuItem.when', 'Condition which must be true to show this item'), type: 'string' @@ -197,8 +206,8 @@ namespace schema { type: 'array', items: menuItem }, - 'comments/commentThread/context': { - description: localize('commentThread.actions', "The contributed comment thread context menu, rendered as buttons below the comment editor"), + 'comments/commentThread/actions': { + description: localize('commentThread.actions', "The contributed comment thread actions"), type: 'array', items: menuItem }, @@ -207,8 +216,8 @@ namespace schema { type: 'array', items: menuItem }, - 'comments/comment/context': { - description: localize('comment.actions', "The contributed comment context menu, rendered as buttons below the comment editor"), + 'comments/comment/actions': { + description: localize('comment.actions', "The contributed comment actions"), type: 'array', items: menuItem }, @@ -220,7 +229,6 @@ namespace schema { export interface IUserFriendlyCommand { command: string; title: string | ILocalizedString; - enablement?: string; category?: string | ILocalizedString; icon?: IUserFriendlyIcon; } @@ -239,10 +247,6 @@ namespace schema { if (!isValidLocalizedString(command.title, collector, 'title')) { return false; } - if (command.enablement && typeof command.enablement !== 'string') { - collector.error(localize('optstring', "property `{0}` can be omitted or must be of type `string`", 'precondition')); - return false; - } if (command.category && !isValidLocalizedString(command.category, collector, 'category')) { return false; } @@ -296,10 +300,6 @@ namespace schema { description: localize('vscode.extension.contributes.commandType.category', '(Optional) Category string by the command is grouped in the UI'), type: 'string' }, - enablement: { - description: localize('vscode.extension.contributes.commandType.precondition', '(Optional) Condition which must be true to enable the command'), - type: 'string' - }, icon: { description: localize('vscode.extension.contributes.commandType.icon', '(Optional) Icon which is used to represent the command in the UI. Either a file path or a themable configuration'), anyOf: [{ @@ -336,12 +336,10 @@ namespace schema { let _commandRegistrations: IDisposable[] = []; -export const commandsExtensionPoint = ExtensionsRegistry.registerExtensionPoint({ +ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'commands', jsonSchema: schema.commandsContribution -}); - -commandsExtensionPoint.setHandler(extensions => { +}).setHandler(extensions => { function handleCommand(userFriendlyCommand: schema.IUserFriendlyCommand, extension: IExtensionPointUser, disposables: IDisposable[]) { @@ -349,7 +347,7 @@ commandsExtensionPoint.setHandler(extensions => { return; } - const { icon, enablement, category, title, command } = userFriendlyCommand; + const { icon, category, title, command } = userFriendlyCommand; let absoluteIcon: { dark: URI; light?: URI; } | undefined; if (icon) { @@ -366,13 +364,7 @@ commandsExtensionPoint.setHandler(extensions => { if (MenuRegistry.getCommand(command)) { extension.collector.info(localize('dup', "Command `{0}` appears multiple times in the `commands` section.", userFriendlyCommand.command)); } - const registration = MenuRegistry.addCommand({ - id: command, - title, - category, - precondition: ContextKeyExpr.deserialize(enablement), - iconLocation: absoluteIcon - }); + const registration = MenuRegistry.addCommand({ id: command, title, category, iconLocation: absoluteIcon }); disposables.push(registration); } @@ -447,6 +439,14 @@ ExtensionsRegistry.registerExtensionPoint<{ [loc: string]: schema.IUserFriendlyM } } + if (item.precondition) { + command.precondition = ContextKeyExpr.deserialize(item.precondition); + } + + if (alt && item.precondition) { + alt.precondition = command.precondition; + } + const registration = MenuRegistry.appendMenuItem(menu, { command, alt, diff --git a/src/vs/workbench/api/browser/extensionHost.contribution.ts b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts similarity index 51% rename from src/vs/workbench/api/browser/extensionHost.contribution.ts rename to src/vs/workbench/api/electron-browser/extensionHost.contribution.ts index 6f9b4734f6..2cb4fd0a1d 100644 --- a/src/vs/workbench/api/browser/extensionHost.contribution.ts +++ b/src/vs/workbench/api/electron-browser/extensionHost.contribution.ts @@ -14,47 +14,47 @@ import { ColorExtensionPoint } from 'vs/workbench/services/themes/common/colorEx import { LanguageConfigurationFileHandler } from 'vs/workbench/contrib/codeEditor/browser/languageConfigurationExtensionPoint'; // --- mainThread participants -import './mainThreadCodeInsets'; -import './mainThreadClipboard'; -import './mainThreadCommands'; -import './mainThreadConfiguration'; -import './mainThreadConsole'; -// import './mainThreadDebugService'; {{SQL CARBON EDIT}} @anthonydresser comment out debug service -import './mainThreadDecorations'; -import './mainThreadDiagnostics'; -import './mainThreadDialogs'; -import './mainThreadDocumentContentProviders'; -import './mainThreadDocuments'; -import './mainThreadDocumentsAndEditors'; -import './mainThreadEditor'; -import './mainThreadEditors'; -import './mainThreadErrors'; -import './mainThreadExtensionService'; -import './mainThreadFileSystem'; -import './mainThreadFileSystemEventService'; -import './mainThreadHeapService'; -import './mainThreadKeytar'; -import './mainThreadLanguageFeatures'; -import './mainThreadLanguages'; -import './mainThreadLogService'; -import './mainThreadMessageService'; -import './mainThreadOutputService'; -import './mainThreadProgress'; -import './mainThreadQuickOpen'; -import './mainThreadSaveParticipant'; -import './mainThreadSCM'; -import './mainThreadSearch'; -import './mainThreadStatusBar'; -import './mainThreadStorage'; -import './mainThreadTelemetry'; -import './mainThreadTerminalService'; -import './mainThreadTreeViews'; -import './mainThreadUrls'; -import './mainThreadWindow'; +import '../browser/mainThreadClipboard'; +import '../browser/mainThreadCommands'; +import '../browser/mainThreadConfiguration'; +import '../browser/mainThreadConsole'; +// {{SQL CARBON EDIT}} +// import '../browser/mainThreadDebugService'; +import '../browser/mainThreadDecorations'; +import '../browser/mainThreadDiagnostics'; +import '../browser/mainThreadDialogs'; +import '../browser/mainThreadDocumentContentProviders'; +import '../browser/mainThreadDocuments'; +import '../browser/mainThreadDocumentsAndEditors'; +import '../browser/mainThreadEditor'; +import '../browser/mainThreadEditors'; +import '../browser/mainThreadErrors'; +import '../browser/mainThreadExtensionService'; +import '../browser/mainThreadFileSystem'; +import '../browser/mainThreadFileSystemEventService'; +import '../browser/mainThreadHeapService'; +import '../browser/mainThreadKeytar'; +import '../browser/mainThreadLanguageFeatures'; +import '../browser/mainThreadLanguages'; +import '../browser/mainThreadLogService'; +import '../browser/mainThreadMessageService'; +import '../browser/mainThreadOutputService'; +import '../browser/mainThreadProgress'; +import '../browser/mainThreadQuickOpen'; +import '../browser/mainThreadSaveParticipant'; +import '../browser/mainThreadSCM'; +import '../browser/mainThreadSearch'; +import '../browser/mainThreadStatusBar'; +import '../browser/mainThreadStorage'; +import '../browser/mainThreadTelemetry'; +import '../browser/mainThreadTerminalService'; +import '../browser/mainThreadTreeViews'; +import '../browser/mainThreadUrls'; +import '../browser/mainThreadWindow'; +import '../browser/mainThreadWorkspace'; +import '../browser/mainThreadComments'; +import '../browser/mainThreadTask'; import './mainThreadWebview'; -import './mainThreadWorkspace'; -import './mainThreadComments'; -import './mainThreadTask'; import 'vs/workbench/api/common/apiCommands'; export class ExtensionPoints implements IWorkbenchContribution { diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts similarity index 75% rename from src/vs/workbench/api/browser/mainThreadWebview.ts rename to src/vs/workbench/api/electron-browser/mainThreadWebview.ts index 52081d8899..833aed5ecc 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/electron-browser/mainThreadWebview.ts @@ -2,27 +2,30 @@ * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ - import { onUnexpectedError } from 'vs/base/common/errors'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import * as map from 'vs/base/common/map'; import { URI, UriComponents } from 'vs/base/common/uri'; +import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import * as modes from 'vs/editor/common/modes'; import { localize } from 'vs/nls'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; +import product from 'vs/platform/product/node/product'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/common/extHost.protocol'; +import { ExtHostContext, ExtHostWebviewsShape, IExtHostContext, MainContext, MainThreadWebviewsShape, WebviewInsetHandle, WebviewPanelHandle, WebviewPanelShowOptions } from 'vs/workbench/api/common/extHost.protocol'; import { editorGroupToViewColumn, EditorViewColumn, viewColumnToEditorGroup } from 'vs/workbench/api/common/shared/editor'; +import { CodeInsetController } from 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; import { WebviewEditor } from 'vs/workbench/contrib/webview/browser/webviewEditor'; import { WebviewEditorInput } from 'vs/workbench/contrib/webview/browser/webviewEditorInput'; import { ICreateWebViewShowOptions, IWebviewEditorService, WebviewInputOptions } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; +import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { extHostNamedCustomer } from '../common/extHostCustomers'; -import { IProductService } from 'vs/platform/product/common/product'; @extHostNamedCustomer(MainContext.MainThreadWebviews) export class MainThreadWebviews extends Disposable implements MainThreadWebviewsShape { @@ -31,8 +34,9 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews 'http', 'https', 'mailto', + product.urlProtocol, 'vscode', - 'vscode-insider', + 'vscode-insiders' ]); private static revivalPool = 0; @@ -40,6 +44,7 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews private readonly _proxy: ExtHostWebviewsShape; private readonly _webviews = new Map(); + private readonly _webviewsElements = new Map(); private readonly _revivers = new Map(); private _activeWebview: WebviewPanelHandle | undefined = undefined; @@ -53,17 +58,18 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews @IWebviewEditorService private readonly _webviewService: IWebviewEditorService, @IOpenerService private readonly _openerService: IOpenerService, @ITelemetryService private readonly _telemetryService: ITelemetryService, - @IProductService private readonly _productService: IProductService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @ICodeEditorService private readonly _codeEditorService: ICodeEditorService, ) { super(); this._proxy = context.getProxy(ExtHostContext.ExtHostWebviews); - this._register(_editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this)); - this._register(_editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this)); + _editorService.onDidActiveEditorChange(this.onActiveEditorChanged, this, this._toDispose); + _editorService.onDidVisibleEditorsChange(this.onVisibleEditorsChanged, this, this._toDispose); // This reviver's only job is to activate webview extensions // This should trigger the real reviver to be registered from the extension host side. - this._register(_webviewService.registerReviver({ + this._toDispose.push(_webviewService.registerReviver({ canRevive: (webview) => { const viewType = webview.state.viewType; if (viewType) { @@ -74,9 +80,9 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews reviveWebview: () => { throw new Error('not implemented'); } })); - this._register(lifecycleService.onBeforeShutdown(e => { + lifecycleService.onBeforeShutdown(e => { e.veto(this._onBeforeShutdown()); - }, this)); + }, this, this._toDispose); } public $createWebviewPanel( @@ -113,6 +119,52 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews this._telemetryService.publicLog('webviews:createWebviewPanel', { extensionId: extensionId.value }); } + $createWebviewCodeInset( + handle: WebviewInsetHandle, + symbolId: string, + options: modes.IWebviewOptions, + extensionId: ExtensionIdentifier, + extensionLocation: UriComponents + ): void { + // todo@joh main is for the lack of a code-inset service + // which we maybe wanna have... this is how it now works + // 1) create webview element + // 2) find the code inset controller that request it + // 3) let the controller adopt the widget + // 4) continue to forward messages to the webview + const webview = this._instantiationService.createInstance( + WebviewElement, + { + extension: { + location: URI.revive(extensionLocation), + id: extensionId + }, + enableFindWidget: false, + }, + { + allowScripts: options.enableScripts, + } + ); + + let found = false; + for (const editor of this._codeEditorService.listCodeEditors()) { + const ctrl = CodeInsetController.get(editor); + if (ctrl && ctrl.acceptWebview(symbolId, webview)) { + found = true; + break; + } + } + + if (!found) { + webview.dispose(); + return; + } + // this will leak... the adopted webview will be disposed by the + // code inset controller. we might need a dispose-event here so that + // we can clean up things. + this._webviewsElements.set(handle, webview); + } + public $disposeWebview(handle: WebviewPanelHandle): void { const webview = this.getWebview(handle); webview.dispose(); @@ -128,14 +180,22 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews webview.iconPath = reviveWebviewIcon(value); } - public $setHtml(handle: WebviewPanelHandle, value: string): void { - const webview = this.getWebview(handle); - webview.html = value; + public $setHtml(handle: WebviewPanelHandle | WebviewInsetHandle, value: string): void { + if (typeof handle === 'number') { + this.getWebviewElement(handle).html = value; + } else { + const webview = this.getWebview(handle); + webview.html = value; + } } - public $setOptions(handle: WebviewPanelHandle, options: modes.IWebviewOptions): void { - const webview = this.getWebview(handle); - webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */)); + public $setOptions(handle: WebviewPanelHandle | WebviewInsetHandle, options: modes.IWebviewOptions): void { + if (typeof handle === 'number') { + this.getWebviewElement(handle).options = reviveWebviewOptions(options as any /*todo@mat */); + } else { + const webview = this.getWebview(handle); + webview.setOptions(reviveWebviewOptions(options as any /*todo@mat */)); + } } public $reveal(handle: WebviewPanelHandle, showOptions: WebviewPanelShowOptions): void { @@ -150,24 +210,29 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews } } - public async $postMessage(handle: WebviewPanelHandle, message: any): Promise { - const webview = this.getWebview(handle); - const editors = this._editorService.visibleControls - .filter(e => e instanceof WebviewEditor) - .map(e => e as WebviewEditor) - .filter(e => e.input!.matches(webview)); - - if (editors.length > 0) { - editors[0].sendMessage(message); + public async $postMessage(handle: WebviewPanelHandle | WebviewInsetHandle, message: any): Promise { + if (typeof handle === 'number') { + this.getWebviewElement(handle).sendMessage(message); return true; - } + } else { + const webview = this.getWebview(handle); + const editors = this._editorService.visibleControls + .filter(e => e instanceof WebviewEditor) + .map(e => e as WebviewEditor) + .filter(e => e.input!.matches(webview)); - if (webview.webview) { - webview.webview.sendMessage(message); - return true; - } + if (editors.length > 0) { + editors[0].sendMessage(message); + return true; + } - return false; + if (webview.webview) { + webview.webview.sendMessage(message); + return true; + } + + return false; + } } public $registerSerializer(viewType: string): void { @@ -319,9 +384,6 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews if (MainThreadWebviews.standardSupportedLinkSchemes.has(link.scheme)) { return true; } - if (this._productService.urlProtocol === link.scheme) { - return true; - } return !!webview.options.enableCommandUris && link.scheme === 'command'; } @@ -333,6 +395,14 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return webview; } + private getWebviewElement(handle: number): WebviewElement { + const webview = this._webviewsElements.get(handle); + if (!webview) { + throw new Error('Unknown webview handle:' + handle); + } + return webview; + } + private static getDeserializationFailedContents(viewType: string) { return ` diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index aa0f8337f7..034baa1f27 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -3,7 +3,6 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import * as nls 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'; @@ -37,7 +36,7 @@ import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionS import { ExtHostFileSystem } from 'vs/workbench/api/common/extHostFileSystem'; import { ExtHostFileSystemEventService } from 'vs/workbench/api/common/extHostFileSystemEventService'; import { ExtHostHeapService } from 'vs/workbench/api/common/extHostHeapService'; -import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures'; +import { ExtHostLanguageFeatures, ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtHostLanguages } from 'vs/workbench/api/common/extHostLanguages'; import { ExtHostLogService } from 'vs/workbench/api/common/extHostLogService'; import { ExtHostMessageService } from 'vs/workbench/api/common/extHostMessageService'; @@ -69,8 +68,6 @@ import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; import { withNullAsUndefined } from 'vs/base/common/types'; import { values } from 'vs/base/common/collections'; import { Schemas } from 'vs/base/common/network'; -import { IURITransformer } from 'vs/base/common/uriIpc'; -import { ExtHostEditorInsets } from 'vs/workbench/api/common/extHostCodeInsets'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -95,7 +92,8 @@ export function createApiFactory( extensionService: ExtHostExtensionService, extHostLogService: ExtHostLogService, extHostStorage: ExtHostStorage, - uriTransformer: IURITransformer | null + schemeTransformer: ISchemeTransformer | null, + outputChannelName: string ): IExtensionApiFactory { // Addressable instances @@ -113,9 +111,8 @@ export function createApiFactory( const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService)); rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace); rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration); - const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors)); const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol)); - const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics, extHostLogService)); + const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, schemeTransformer, extHostDocuments, extHostCommands, extHostHeapService, extHostDiagnostics, extHostLogService)); const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures)); const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostDocumentsAndEditors)); const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands)); @@ -124,7 +121,7 @@ export function createApiFactory( // const extHostDebugService = rpcProtocol.set(ExtHostContext.ExtHostDebugService, new ExtHostDebugService(rpcProtocol, extHostWorkspace, extensionService, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService, extHostCommands)); const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService)); const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments)); - const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, uriTransformer, extHostLogService)); + const extHostSearch = rpcProtocol.set(ExtHostContext.ExtHostSearch, new ExtHostSearch(rpcProtocol, schemeTransformer, extHostLogService)); const extHostTask = rpcProtocol.set(ExtHostContext.ExtHostTask, new ExtHostTask(rpcProtocol, extHostWorkspace, extHostDocumentsAndEditors, extHostConfiguration, extHostTerminalService)); const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol)); rpcProtocol.set(ExtHostContext.ExtHostExtensionService, extensionService); @@ -157,7 +154,6 @@ export function createApiFactory( const extHostLanguages = new ExtHostLanguages(rpcProtocol, extHostDocuments); // Register an output channel for exthost log - const outputChannelName = initData.remoteAuthority ? nls.localize('remote extension host Log', "Remote Extension Host") : nls.localize('extension host Log', "Extension Host"); extHostOutputService.createOutputChannelFromLogFile(outputChannelName, extHostLogService.logFile); // Register API-ish commands @@ -167,7 +163,7 @@ export function createApiFactory( // Check document selectors for being overly generic. Technically this isn't a problem but // in practice many extensions say they support `fooLang` but need fs-access to do so. Those - // extension should specify then the `file`-scheme, e.g. `{ scheme: 'fooLang', language: 'fooLang' }` + // extension should specify then the `file`-scheme, e.g `{ scheme: 'fooLang', language: 'fooLang' }` // We only inform once, it is not a warning because we just want to raise awareness and because // we cannot say if the extension is doing it right or wrong... const checkSelector = (function () { @@ -243,7 +239,7 @@ export function createApiFactory( }; // namespace: env - const env: typeof vscode.env = { + const env: typeof vscode.env = Object.freeze({ get machineId() { return initData.telemetryInfo.machineId; }, get sessionId() { return initData.telemetryInfo.sessionId; }, get language() { return initData.environment.appLanguage; }, @@ -264,11 +260,7 @@ export function createApiFactory( openExternal(uri: URI) { return extHostWindow.openUri(uri, { allowTunneling: !!initData.remoteAuthority }); } - }; - if (!initData.environment.extensionTestsLocationURI) { - // allow to patch env-function when running tests - Object.freeze(env); - } + }); // namespace: extensions const extensions: typeof vscode.extensions = { @@ -313,6 +305,10 @@ export function createApiFactory( registerCodeLensProvider(selector: vscode.DocumentSelector, provider: vscode.CodeLensProvider): vscode.Disposable { return extHostLanguageFeatures.registerCodeLensProvider(extension, checkSelector(selector), provider); }, + registerCodeInsetProvider(selector: vscode.DocumentSelector, provider: vscode.CodeInsetProvider): vscode.Disposable { + checkProposedApiEnabled(extension); + return extHostLanguageFeatures.registerCodeInsetProvider(extension, checkSelector(selector), provider); + }, registerDefinitionProvider(selector: vscode.DocumentSelector, provider: vscode.DefinitionProvider): vscode.Disposable { return extHostLanguageFeatures.registerDefinitionProvider(extension, checkSelector(selector), provider); }, @@ -474,10 +470,7 @@ export function createApiFactory( return extHostDialogs.showSaveDialog(options); }, createStatusBarItem(position?: vscode.StatusBarAlignment, priority?: number): vscode.StatusBarItem { - const id = extension.identifier.value; - const name = nls.localize('extensionLabel', "{0} (Extension)", extension.displayName || extension.name); - - return extHostStatusBar.createStatusBarEntry(id, name, position, priority); + return extHostStatusBar.createStatusBarEntry(extension.identifier, position, priority); }, setStatusBarMessage(text: string, timeoutOrThenable?: number | Thenable): vscode.Disposable { return extHostStatusBar.setStatusBarMessage(text, timeoutOrThenable); @@ -495,14 +488,9 @@ export function createApiFactory( createWebviewPanel(viewType: string, title: string, showOptions: vscode.ViewColumn | { viewColumn: vscode.ViewColumn, preserveFocus?: boolean }, options: vscode.WebviewPanelOptions & vscode.WebviewOptions): vscode.WebviewPanel { return extHostWebviews.createWebviewPanel(extension, viewType, title, showOptions, options); }, - createWebviewTextEditorInset(editor: vscode.TextEditor, range: vscode.Range, options: vscode.WebviewOptions): vscode.WebviewEditorInset { - checkProposedApiEnabled(extension); - return extHostEditorInsets.createWebviewEditorInset(editor, range, options); - }, createTerminal(nameOrOptions?: vscode.TerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { if (typeof nameOrOptions === 'object') { - nameOrOptions.runInBackground = nameOrOptions.runInBackground && extension.enableProposedApi; - return extHostTerminalService.createTerminalFromOptions(nameOrOptions); + return extHostTerminalService.createTerminalFromOptions(nameOrOptions); } return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs); }, diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 84d4cc993f..56e16d3aeb 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -33,10 +33,10 @@ import { IWorkspace } from 'vs/platform/workspace/common/workspace'; import { Schemas } from 'vs/base/common/network'; import { withNullAsUndefined } from 'vs/base/common/types'; import { VSBuffer } from 'vs/base/common/buffer'; +import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento'; import { ExtensionStoragePaths } from 'vs/workbench/api/node/extHostStoragePaths'; import { RemoteAuthorityResolverError, ExtensionExecutionContext } from 'vs/workbench/api/common/extHostTypes'; -import { IURITransformer } from 'vs/base/common/uriIpc'; interface ITestRunner { run(testsRoot: string, clb: (error: Error, failures?: number) => void): void; @@ -86,7 +86,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { extHostConfiguration: ExtHostConfiguration, environment: IEnvironment, extHostLogService: ExtHostLogService, - uriTransformer: IURITransformer | null + schemeTransformer: ISchemeTransformer | null, + outputChannelName: string ) { this._hostUtils = hostUtils; this._initData = initData; @@ -136,7 +137,8 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { this, this._extHostLogService, this._storage, - uriTransformer + schemeTransformer, + outputChannelName ); this._resolvers = Object.create(null); diff --git a/src/vs/workbench/api/node/extHostOutputService.ts b/src/vs/workbench/api/node/extHostOutputService.ts index 0114cf10d9..d176cac5e8 100644 --- a/src/vs/workbench/api/node/extHostOutputService.ts +++ b/src/vs/workbench/api/node/extHostOutputService.ts @@ -51,7 +51,7 @@ export const LogOutputChannelFactory = new class implements IOutputChannelFactor try { const outputDirPath = join(logsLocation.fsPath, `output_logging_${toLocalISOString(new Date()).replace(/-|:|\.\d+Z$/g, '')}`); const outputDir = await dirExists(outputDirPath).then(exists => exists ? exists : mkdirp(outputDirPath).then(() => true)).then(() => outputDirPath); - const fileName = `${this._namePool++}-${name.replace(/[\\/:\*\?"<>\|]/g, '')}`; + const fileName = `${this._namePool++}-${name}`; const file = URI.file(join(outputDir, `${fileName}.log`)); const appender = new OutputAppender(fileName, file.fsPath); return new ExtHostOutputChannelBackedByFile(name, appender, proxy); diff --git a/src/vs/workbench/api/node/extHostSearch.ts b/src/vs/workbench/api/node/extHostSearch.ts index 238a2c71f3..223d432056 100644 --- a/src/vs/workbench/api/node/extHostSearch.ts +++ b/src/vs/workbench/api/node/extHostSearch.ts @@ -16,7 +16,10 @@ import { OutputChannel } from 'vs/workbench/services/search/node/ripgrepSearchUt import { TextSearchManager } from 'vs/workbench/services/search/node/textSearchManager'; import * as vscode from 'vscode'; import { ExtHostSearchShape, IMainContext, MainContext, MainThreadSearchShape } from '../common/extHost.protocol'; -import { IURITransformer } from 'vs/base/common/uriIpc'; + +export interface ISchemeTransformer { + transformOutgoing(scheme: string): string; +} export class ExtHostSearch implements ExtHostSearchShape { @@ -32,14 +35,14 @@ export class ExtHostSearch implements ExtHostSearchShape { private _fileSearchManager: FileSearchManager; - constructor(mainContext: IMainContext, private _uriTransformer: IURITransformer | null, private _logService: ILogService, private _pfs = pfs) { + constructor(mainContext: IMainContext, private _schemeTransformer: ISchemeTransformer | null, private _logService: ILogService, private _pfs = pfs) { this._proxy = mainContext.getProxy(MainContext.MainThreadSearch); this._fileSearchManager = new FileSearchManager(); } private _transformScheme(scheme: string): string { - if (this._uriTransformer) { - return this._uriTransformer.transformOutgoingScheme(scheme); + if (this._schemeTransformer) { + return this._schemeTransformer.transformOutgoing(scheme); } return scheme; } diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index 5894a499ba..a39e90bfea 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -714,7 +714,7 @@ export class ExtHostTask implements ExtHostTaskShape { paths[i] = resolver.resolve(ws, paths[i]); } } - result.process = await win32.findExecutable( + result.process = win32.findExecutable( resolver.resolve(ws, toResolve.process.name), toResolve.process.cwd !== undefined ? resolver.resolve(ws, toResolve.process.cwd) : undefined, paths diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index 2deaf0fe8f..cc2f1465f7 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -115,10 +115,9 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi cwd?: string | URI, env?: { [key: string]: string | null }, waitOnExit?: boolean, - strictEnv?: boolean, - runInBackground?: boolean + strictEnv?: boolean ): void { - this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, runInBackground).then(terminal => { + this._proxy.$createTerminal(this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv).then(terminal => { this._name = terminal.name; this._runQueuedRequests(terminal.id); }); @@ -177,7 +176,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi this._pidPromiseComplete(processId); this._pidPromiseComplete = null; } else { - // Recreate the promise if this is the nth processId set (e.g. reused task terminals) + // Recreate the promise if this is the nth processId set (eg. reused task terminals) this._pidPromise.then(pid => { if (pid !== processId) { this._pidPromise = Promise.resolve(processId); @@ -310,7 +309,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { public createTerminalFromOptions(options: vscode.TerminalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, options.name); - terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv, options.runInBackground); + terminal.create(options.shellPath, options.shellArgs, options.cwd, options.env, /*options.waitOnExit*/ undefined, options.strictEnv); this._terminals.push(terminal); return terminal; } diff --git a/src/vs/workbench/browser/actions.ts b/src/vs/workbench/browser/actions.ts index c0171828b4..31bbb9bb53 100644 --- a/src/vs/workbench/browser/actions.ts +++ b/src/vs/workbench/browser/actions.ts @@ -24,7 +24,7 @@ export class ActionBarContributor { /** * Returns an array of primary actions in the given context. */ - getActions(context: unknown): ReadonlyArray { + getActions(context: unknown): IAction[] { return []; } } @@ -66,7 +66,7 @@ export class ContributableActionProvider implements IActionProvider { return false; } - getActions(tree: ITree, element: unknown): ReadonlyArray { + getActions(tree: ITree, element: unknown): IAction[] { const actions: IAction[] = []; const context = this.toContext(tree, element); @@ -155,7 +155,7 @@ export interface IActionBarRegistry { class ActionBarRegistry implements IActionBarRegistry { private readonly actionBarContributorConstructors: { scope: string; ctor: IConstructorSignature0; }[] = []; - private readonly actionBarContributorInstances: Map = new Map(); + private readonly actionBarContributorInstances: { [scope: string]: ActionBarContributor[] } = Object.create(null); private instantiationService: IInstantiationService; start(accessor: ServicesAccessor): void { @@ -169,16 +169,15 @@ class ActionBarRegistry implements IActionBarRegistry { private createActionBarContributor(scope: string, ctor: IConstructorSignature0): void { const instance = this.instantiationService.createInstance(ctor); - let target = this.actionBarContributorInstances.get(scope); + let target = this.actionBarContributorInstances[scope]; if (!target) { - target = []; - this.actionBarContributorInstances.set(scope, target); + target = this.actionBarContributorInstances[scope] = []; } target.push(instance); } private getContributors(scope: string): ActionBarContributor[] { - return this.actionBarContributorInstances.get(scope) || []; + return this.actionBarContributorInstances[scope] || []; } registerActionBarContributor(scope: string, ctor: IConstructorSignature0): void { diff --git a/src/vs/workbench/browser/actions/layoutActions.ts b/src/vs/workbench/browser/actions/layoutActions.ts index ac464da84a..a6d1f5cede 100644 --- a/src/vs/workbench/browser/actions/layoutActions.ts +++ b/src/vs/workbench/browser/actions/layoutActions.ts @@ -21,9 +21,8 @@ import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { isWindows, isLinux } from 'vs/base/common/platform'; import { IsMacContext } from 'vs/workbench/browser/contextkeys'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; -import { InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor'; +import { InEditorZenModeContext } from 'vs/workbench/common/editor'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; const registry = Registry.as(Extensions.WorkbenchActions); const viewCategory = nls.localize('view', "View"); @@ -62,8 +61,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleActivityBarVisibilityAction.ID, - title: nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"), - toggled: ContextKeyExpr.equals('config.workbench.activityBar.visible', true) + title: nls.localize({ key: 'miToggleActivityBar', comment: ['&& denotes a mnemonic'] }, "Toggle &&Activity Bar") }, order: 4 }); @@ -97,8 +95,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', command: { id: ToggleCenteredLayout.ID, - title: nls.localize('miToggleCenteredLayout', "Centered Layout"), - toggled: IsCenteredLayoutContext + title: nls.localize('miToggleCenteredLayout', "Toggle Centered Layout") }, order: 3 }); @@ -206,22 +203,11 @@ export class ToggleSidebarPositionAction extends Action { registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleSidebarPositionAction, ToggleSidebarPositionAction.ID, ToggleSidebarPositionAction.LABEL), 'View: Toggle Side Bar Position', viewCategory); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_workbench_layout_move', + group: '2_workbench_layout', command: { id: ToggleSidebarPositionAction.ID, - title: nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right") + title: nls.localize({ key: 'miMoveSidebarLeftRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left/Right") }, - when: ContextKeyExpr.notEquals('config.workbench.sideBar.location', 'right'), - order: 2 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_workbench_layout_move', - command: { - id: ToggleSidebarPositionAction.ID, - title: nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left") - }, - when: ContextKeyExpr.equals('config.workbench.sideBar.location', 'right'), order: 2 }); @@ -280,15 +266,14 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleSidebarVisibilityAction.ID, - title: nls.localize({ key: 'miShowSidebar', comment: ['&& denotes a mnemonic'] }, "Show &&Side Bar"), - toggled: SideBarVisibleContext + title: nls.localize({ key: 'miToggleSidebar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Side Bar") }, order: 1 }); // --- Toggle Statusbar Visibility -export class ToggleStatusbarVisibilityAction extends Action { +class ToggleStatusbarVisibilityAction extends Action { static readonly ID = 'workbench.action.toggleStatusbarVisibility'; static readonly LABEL = nls.localize('toggleStatusbar', "Toggle Status Bar Visibility"); @@ -320,8 +305,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: ToggleStatusbarVisibilityAction.ID, - title: nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "Show S&&tatus Bar"), - toggled: ContextKeyExpr.equals('config.workbench.statusBar.visible', true) + title: nls.localize({ key: 'miToggleStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Toggle Status Bar") }, order: 3 }); @@ -386,8 +370,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '1_toggle_view', command: { id: ToggleZenMode.ID, - title: nls.localize('miToggleZenMode', "Zen Mode"), - toggled: InEditorZenModeContext + title: nls.localize('miToggleZenMode', "Toggle Zen Mode") }, order: 2 }); @@ -444,13 +427,13 @@ if (isWindows || isLinux) { } MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '2_workbench_layout', + group: '1_toggle_view', command: { id: ToggleMenuBarAction.ID, - title: nls.localize({ key: 'miShowMenuBar', comment: ['&& denotes a mnemonic'] }, "Show Menu &&Bar"), - toggled: ContextKeyExpr.and(IsMacContext.toNegated(), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'hidden'), ContextKeyExpr.notEquals('config.window.menuBarVisibility', 'toggle')) + title: nls.localize({ key: 'miToggleMenuBar', comment: ['&& denotes a mnemonic'] }, "Toggle Menu &&Bar") }, - order: 0 + when: IsMacContext.toNegated(), + order: 4 }); // --- Resize View diff --git a/src/vs/workbench/browser/composite.ts b/src/vs/workbench/browser/composite.ts index fac3d53815..8a08fb6582 100644 --- a/src/vs/workbench/browser/composite.ts +++ b/src/vs/workbench/browser/composite.ts @@ -150,7 +150,7 @@ export abstract class Composite extends Component implements IComposite { /** * Returns an array of actions to show in the action bar of the composite. */ - getActions(): ReadonlyArray { + getActions(): IAction[] { return []; } @@ -158,14 +158,14 @@ export abstract class Composite extends Component implements IComposite { * Returns an array of actions to show in the action bar of the composite * in a less prominent way then action from getActions. */ - getSecondaryActions(): ReadonlyArray { + getSecondaryActions(): IAction[] { return []; } /** * Returns an array of actions to show in the context menu of the composite */ - getContextMenuActions(): ReadonlyArray { + getContextMenuActions(): IAction[] { return []; } diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index 62b64596c9..4d11c2605e 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IContextKeyService, IContextKey, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { InputFocusedContext } from 'vs/platform/contextkey/common/contextkeys'; import { IWindowsConfiguration } from 'vs/platform/windows/common/windows'; -import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext, IsCenteredLayoutContext } from 'vs/workbench/common/editor'; +import { ActiveEditorContext, EditorsVisibleContext, TextCompareEditorVisibleContext, TextCompareEditorActiveContext, ActiveEditorGroupEmptyContext, MultipleEditorGroupsContext, TEXT_DIFF_EDITOR_ID, SplitEditorsVertically, InEditorZenModeContext } from 'vs/workbench/common/editor'; import { trackFocus, addDisposableListener, EventType } from 'vs/base/browser/dom'; import { preferredSideBySideGroupDirection, GroupDirection, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -16,10 +16,9 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { SideBarVisibleContext } from 'vs/workbench/common/viewlet'; -import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/layout/browser/layoutService'; +import { IWorkbenchLayoutService, Parts } from 'vs/workbench/services/layout/browser/layoutService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { isMacintosh, isLinux, isWindows } from 'vs/base/common/platform'; -import { PanelPositionContext } from 'vs/workbench/common/panel'; export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); @@ -39,8 +38,6 @@ export const WorkspaceFolderCountContext = new RawContextKey('workspaceF export const RemoteFileDialogContext = new RawContextKey('remoteFileDialogVisible', false); -export const IsFullscreenContext = new RawContextKey('isFullscreen', false); - export class WorkbenchContextKeysHandler extends Disposable { private inputFocusedContext: IContextKey; @@ -57,10 +54,8 @@ export class WorkbenchContextKeysHandler extends Disposable { private inZenModeContext: IContextKey; - private isFullscreenContext: IContextKey; - private isCenteredLayoutContext: IContextKey; + private sideBarVisibleContext: IContextKey; - private panelPositionContext: IContextKey; constructor( @IContextKeyService private contextKeyService: IContextKeyService, @@ -98,9 +93,6 @@ export class WorkbenchContextKeysHandler extends Disposable { })); this._register(this.layoutService.onZenModeChange(enabled => this.inZenModeContext.set(enabled))); - this._register(this.layoutService.onFullscreenChange(fullscreen => this.isFullscreenContext.set(fullscreen))); - this._register(this.layoutService.onCenteredLayoutChange(centered => this.isCenteredLayoutContext.set(centered))); - this._register(this.layoutService.onPanelPositionChange(position => this.panelPositionContext.set(position))); this._register(this.viewletService.onDidViewletClose(() => this.updateSideBarContextKeys())); this._register(this.viewletService.onDidViewletOpen(() => this.updateSideBarContextKeys())); @@ -148,21 +140,11 @@ export class WorkbenchContextKeysHandler extends Disposable { this.splitEditorsVerticallyContext = SplitEditorsVertically.bindTo(this.contextKeyService); this.updateSplitEditorsVerticallyContext(); - // Fullscreen - this.isFullscreenContext = IsFullscreenContext.bindTo(this.contextKeyService); - // Zen Mode this.inZenModeContext = InEditorZenModeContext.bindTo(this.contextKeyService); - // Centered Layout - this.isCenteredLayoutContext = IsCenteredLayoutContext.bindTo(this.contextKeyService); - // Sidebar this.sideBarVisibleContext = SideBarVisibleContext.bindTo(this.contextKeyService); - - // Panel Position - this.panelPositionContext = PanelPositionContext.bindTo(this.contextKeyService); - this.panelPositionContext.set(this.layoutService.getPanelPosition() === Position.RIGHT ? 'right' : 'bottom'); } private updateEditorContextKeys(): void { diff --git a/src/vs/workbench/browser/labels.ts b/src/vs/workbench/browser/labels.ts index 56dd165d5c..bd043e6d97 100644 --- a/src/vs/workbench/browser/labels.ts +++ b/src/vs/workbench/browser/labels.ts @@ -94,8 +94,7 @@ export class ResourceLabels extends Disposable { @IModelService private readonly modelService: IModelService, @IDecorationsService private readonly decorationsService: IDecorationsService, @IThemeService private readonly themeService: IThemeService, - @IFileService private readonly fileService: IFileService, - @ILabelService private readonly labelService: ILabelService + @IFileService private readonly fileService: IFileService ) { super(); @@ -146,10 +145,6 @@ export class ResourceLabels extends Disposable { this._widgets.forEach(widget => widget.notifyFileAssociationsChange()); } })); - - this._register(this.labelService.onDidChangeFormatters(() => { - this._widgets.forEach(widget => widget.notifyFormattersChange()); - })); } get(index: number): IResourceLabel { @@ -217,10 +212,9 @@ export class ResourceLabel extends ResourceLabels { @IModelService modelService: IModelService, @IDecorationsService decorationsService: IDecorationsService, @IThemeService themeService: IThemeService, - @IFileService fileService: IFileService, - @ILabelService labelService: ILabelService + @IFileService fileService: IFileService ) { - super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService, fileService, labelService); + super(DEFAULT_LABELS_CONTAINER, instantiationService, extensionService, configurationService, modelService, decorationsService, themeService, fileService); this._label = this._register(this.create(container, options)); } @@ -315,10 +309,6 @@ class ResourceLabelWidget extends IconLabel { this.render(true); } - notifyFormattersChange(): void { - this.render(false); - } - setResource(label: IResourceLabelProps, options?: IResourceLabelOptions): void { const hasResourceChanged = this.hasResourceChanged(label, options); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index b17487feaa..a4c0b5b4de 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,11 +5,11 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; -import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size, EventHelper } from 'vs/base/browser/dom'; +import { EventType, addDisposableListener, addClass, removeClass, isAncestor, getClientArea, position, size } from 'vs/base/browser/dom'; import { onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { IBackupFileService } from 'vs/workbench/services/backup/common/backup'; import { Registry } from 'vs/platform/registry/common/platform'; -import { isWindows, isLinux, isMacintosh, isWeb } from 'vs/base/common/platform'; +import { isWindows, isLinux, isMacintosh } from 'vs/base/common/platform'; import { pathsToEditors } from 'vs/workbench/common/editor'; import { SidebarPart } from 'vs/workbench/browser/parts/sidebar/sidebarPart'; import { PanelPart } from 'vs/workbench/browser/parts/panel/panelPart'; @@ -43,10 +43,7 @@ enum Settings { SIDEBAR_POSITION = 'workbench.sideBar.location', PANEL_POSITION = 'workbench.panel.defaultLocation', - ZEN_MODE_RESTORE = 'zenMode.restore', - - // TODO @misolori remove before shipping stable - ICON_EXPLORATION_ENABLED = 'workbench.iconExploration.enabled' + ZEN_MODE_RESTORE = 'zenMode.restore' } enum Storage { @@ -66,17 +63,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private readonly _onTitleBarVisibilityChange: Emitter = this._register(new Emitter()); get onTitleBarVisibilityChange(): Event { return this._onTitleBarVisibilityChange.event; } - private readonly _onZenModeChange: Emitter = this._register(new Emitter()); - get onZenModeChange(): Event { return this._onZenModeChange.event; } - - private readonly _onFullscreenChange: Emitter = this._register(new Emitter()); - get onFullscreenChange(): Event { return this._onFullscreenChange.event; } - - private readonly _onCenteredLayoutChange: Emitter = this._register(new Emitter()); - get onCenteredLayoutChange(): Event { return this._onCenteredLayoutChange.event; } - - private readonly _onPanelPositionChange: Emitter = this._register(new Emitter()); - get onPanelPositionChange(): Event { return this._onPanelPositionChange.event; } + private readonly _onZenMode: Emitter = this._register(new Emitter()); + get onZenModeChange(): Event { return this._onZenMode.event; } private readonly _onLayout = this._register(new Emitter()); get onLayout(): Event { return this._onLayout.event; } @@ -160,11 +148,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi wasSideBarVisible: false, wasPanelVisible: false, transitionDisposeables: [] as IDisposable[] - }, - - // TODO @misolori remove before shipping stable - iconExploration: { - enabled: false } }; @@ -223,11 +206,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Prevent workbench from scrolling #55456 this._register(addDisposableListener(this.container, EventType.SCROLL, () => this.container.scrollTop = 0)); - // Prevent native context menus in web #73781 - if (isWeb) { - this._register(addDisposableListener(this.container, EventType.CONTEXT_MENU, (e) => EventHelper.stop(e, true))); - } - // Menubar visibility changes if ((isWindows || isLinux) && getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { this._register(this.titleService.onMenubarVisibilityChange(visible => this.onMenubarToggled(visible))); @@ -264,8 +242,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._onTitleBarVisibilityChange.fire(); this.layout(); // handle title bar when fullscreen changes } - - this._onFullscreenChange.fire(this.state.fullscreen); } private doUpdateLayoutConfiguration(skipLayout?: boolean): void { @@ -298,12 +274,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Menubar visibility const newMenubarVisibility = this.configurationService.getValue(Settings.MENUBAR_VISIBLE); this.setMenubarVisibility(newMenubarVisibility, !!skipLayout); - - // TODO @misolori remove before shipping stable - // Icon exploration on setting change - const newIconExplorationEnabled = this.configurationService.getValue(Settings.ICON_EXPLORATION_ENABLED); - this.setIconExploration(newIconExplorationEnabled); - } private setSideBarPosition(position: Position): void { @@ -416,11 +386,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Zen mode enablement this.state.zenMode.restore = this.storageService.getBoolean(Storage.ZEN_MODE_ENABLED, StorageScope.WORKSPACE, false) && this.configurationService.getValue(Settings.ZEN_MODE_RESTORE); - - // TODO @misolori remove before shipping stable - // Icon exploration - this.state.iconExploration.enabled = this.configurationService.getValue(Settings.ICON_EXPLORATION_ENABLED); - this.setIconExploration(this.state.iconExploration.enabled); } private resolveEditorsToOpen(fileService: IFileService): Promise | IResourceEditor[] { @@ -666,7 +631,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } // Event - this._onZenModeChange.fire(this.state.zenMode.active); + this._onZenMode.fire(this.state.zenMode.active); } private setStatusBarHidden(hidden: boolean, skipLayout?: boolean): void { @@ -689,19 +654,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } } - // TODO @misolori remove before shipping stable - private setIconExploration(enabled: boolean): void { - this.state.iconExploration.enabled = enabled; - - // Update DOM - if (enabled) { - document.body.dataset.exploration = 'icon-exploration'; - } else { - document.body.dataset.exploration = ''; - } - - } - protected createWorkbenchLayout(instantiationService: IInstantiationService): void { const titleBar = this.getPart(Parts.TITLEBAR_PART); const editorPart = this.getPart(Parts.EDITOR_PART); @@ -876,8 +828,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this.layout(); } } - - this._onCenteredLayoutChange.fire(this.state.editor.centered); } resizePart(part: Parts, sizeChange: number): void { @@ -1119,8 +1069,6 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi } else { this.workbenchGrid.layout(); } - - this._onPanelPositionChange.fire(positionToString(this.state.panel.position)); } private savePanelDimension(): void { diff --git a/src/vs/workbench/browser/legacyLayout.ts b/src/vs/workbench/browser/legacyLayout.ts index f1e6c8c1ea..ea2a2ed200 100644 --- a/src/vs/workbench/browser/legacyLayout.ts +++ b/src/vs/workbench/browser/legacyLayout.ts @@ -10,14 +10,14 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storag import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; import { Disposable } from 'vs/base/common/lifecycle'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { isMacintosh, isWeb } from 'vs/base/common/platform'; +import { isMacintosh } from 'vs/base/common/platform'; import { memoize } from 'vs/base/common/decorators'; import { Dimension, getClientArea, size, position, hide, show } from 'vs/base/browser/dom'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { getZoomFactor } from 'vs/base/browser/browser'; import { Part } from 'vs/workbench/browser/part'; -const TITLE_BAR_HEIGHT = isMacintosh && !isWeb ? 22 : 30; +const TITLE_BAR_HEIGHT = isMacintosh ? 22 : 30; const STATUS_BAR_HEIGHT = 22; const ACTIVITY_BAR_WIDTH = 50; diff --git a/src/vs/workbench/browser/media/icons.css b/src/vs/workbench/browser/media/icons.css deleted file mode 100644 index a71f316bc9..0000000000 --- a/src/vs/workbench/browser/media/icons.css +++ /dev/null @@ -1,1221 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -/**************** - Colors -****************/ -:root { - --blue: #00539c; - --gray: #424242; - --grayLight: #848484; - --green: #388a34; - --greenLight: #9cce9c; - --orange: #c27d1a; - --orangeLight: #ff8e00; - --purple: #652d90; - --red: #a31515; - --redLight: #e51400; - --yellow: #fc0; -} - -:root .vs-dark { - --blue: #75beff; - --gray: #c5c5c5; - --grayLight: #848484; - --green: #89d185; - --greenLight: #9cce9c; - --orange: #e8ab53; - --orangeLight: #ff8e00; - --purple: #b180d7; - --red: #f48771; - --redLight: #e51400; - --yellow: #fc0; -} - - -/**************** - Base -****************/ -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header[aria-label="Open Editors Section"] > .actions .action-label.icon, -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.explorer-action.icon, -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.toolbar-toggle-more.icon, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label^="Explorer"] .icon, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Search actions"] .icon, -body[data-exploration^="icon-exploration"] .monaco-findInput > .controls .monaco-custom-checkbox::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .search-view .query-details .file-types .controls > .monaco-custom-checkbox.useExcludesAndIgnoreFiles::before, -body[data-exploration^="icon-exploration"] .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude::before, -body[data-exploration^="icon-exploration"] .search-view .search-widget .replace-container .monaco-action-bar .action-item .icon, -body[data-exploration^="icon-exploration"] .search-view a[class^="action-"], -body[data-exploration^="icon-exploration"] .monaco-workbench .search-view .query-details .more, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Source Control: Git actions"] .icon[data-title="git.commit"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Source Control: Git actions"] .icon[data-title="git.refresh"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label="Debug actions"] .icon, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .actions-container[aria-label^="Extensions"] .icon, -body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title^="git."], -body[data-exploration^="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .content > .debug-viewlet .actions .action-label.icon, -body[data-exploration^="icon-exploration"] .monaco-workbench .debug-toolbar .drag-area, -body[data-exploration^="icon-exploration"] .monaco-workbench .debug-toolbar .action-label, -body[data-exploration^="icon-exploration"] .debug-breakpoint, -body[data-exploration^="icon-exploration"] .debug-viewlet .debug-breakpoints .breakpoint > .icon, -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-item .action-label.extension-action.manage, -body[data-exploration^="icon-exploration"] .extension-ratings > .star, -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon, -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle .octicon, -body[data-exploration^="icon-exploration"] .monaco-toolbar .action-label.toolbar-toggle-more, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.panel > .title > .title-actions .monaco-action-bar .action-item .action-label, -body[data-exploration^="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .symbol-icon::before, -body[data-exploration^="icon-exploration"] .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close, -body[data-exploration^="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore, -body[data-exploration^="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .icon.error, -body[data-exploration^="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .icon.warning, -body[data-exploration^="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item-icon, -body[data-exploration^="icon-exploration"] .monaco-workbench > .notifications-center > .notifications-center-header .clear-all-notifications-action, -body[data-exploration^="icon-exploration"] .monaco-workbench > .notifications-center > .notifications-center-header .hide-all-notifications-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .clear-notification-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .expand-notification-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .collapse-notification-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .action-label, -body[data-exploration^="icon-exploration"] .markers-panel .marker-icon, -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .actions .action-label.icon.markers-panel-action-quickfix, -body[data-exploration^="icon-exploration"] .monaco-tl-twistie.collapsible:not(.loading), -body[data-exploration^="icon-exploration"] .file-icon-themable-tree .monaco-tree-row.has-children .content::before, -body[data-exploration^="icon-exploration"] .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before, -body[data-exploration^="icon-exploration"] .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before, -body[data-exploration^="icon-exploration"] .monaco-tl-twistie.collapsible.collapsed:not(.loading), -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .close-editor-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.closeActiveEditor"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.splitEditor"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="git.openChange"], -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace-all::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .previous::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .next::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .close-fw::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .expand::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .collapse::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .monaco-checkbox .label::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .quick-open-sidebyside-vertical, -body[data-exploration^="icon-exploration"] .monaco-tree-action.collapse-all, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-breakpoint, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-focused-stack-frame, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-top-stack-frame, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-breakpoint-hint, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-breakpoint-conditional, -body[data-exploration^="icon-exploration"] .monaco-editor .debug-breakpoint-log, -body[data-exploration^="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .severity-icon, -body[data-exploration^="icon-exploration"] .monaco-editor .margin-view-overlays .folding, -body[data-exploration^="icon-exploration"] .monaco-workbench .explorer-action.save-all, -body[data-exploration^="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="git.init"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="_workbench.openUserSettingsEditor"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.compareEditor.previousChange"], -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.icon[data-title="git.commit"], -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.icon[data-title="git.refresh"], -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-up, -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-down, -body[data-exploration^="icon-exploration"] .monaco-workbench .explorer-viewlet .action-close-all-files, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more, -body[data-exploration^="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .clear-input, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.openGlobalKeybindingsFile"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="settings.switchToJSON"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="markdown.showSource"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label.file-icon[title^="Preview"]::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="markdown.showPreviewToSide"], -body[data-exploration^="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label, -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.compareEditor.nextChange"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.compareEditor.previousChange"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.compareEditor.nextChange"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="git.openFile"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="git.openFile"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.openGlobalKeybindings"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="toggle.diff.ignoreTrimWhitespace"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="toggle.diff.ignoreTrimWhitespace"], -body[data-exploration^="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon[data-title="peekview.close"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.splitEditor"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="git.openChange"], -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover, -body[data-exploration^="icon-exploration"] .monaco-workbench .explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .close-editor-action, -body[data-exploration^="icon-exploration"] .monaco-workbench .explorer-viewlet .explorer-open-editors .close-editor-action { - background-image: none; - background: var(--gray); - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - -webkit-mask-size: 16px; -} - -/* Center via Flexbox + Search expand */ -body[data-exploration^="icon-exploration"] .search-view .search-widget .toggle-replace-button.collapse, -body[data-exploration^="icon-exploration"] .search-view .search-widget .toggle-replace-button.expand, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace-all, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .previous, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .next, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .close-fw, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .expand, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .collapse, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .monaco-checkbox .label { - display: flex; - align-items: center; - justify-content: center; - background-image: none !important; -} - -/* Before elements */ -body[data-exploration^="icon-exploration"] .search-view .search-widget .toggle-replace-button.collapse::before, -body[data-exploration^="icon-exploration"] .search-view .search-widget .toggle-replace-button.expand::before, -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace-all::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .replace::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .previous::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .next::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .close-fw::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .expand::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .collapse::before, -body[data-exploration^="icon-exploration"] .monaco-editor .find-widget .monaco-checkbox .label::before, -body[data-exploration^="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .monaco-custom-checkbox::before { - content: ""; - width: 16px; - height: 16px; - background-color: var(--gray); - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - -webkit-mask-size: 16px; -} - -/* For icons that are a custom checkbox and use focus */ -body[data-exploration^="icon-exploration"] .monaco-findInput > .controls .monaco-custom-checkbox, -body[data-exploration^="icon-exploration"] .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude, -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header, -body[data-exploration^="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .monaco-custom-checkbox { - background-image: none !important; -} - -body[data-exploration^="icon-exploration"] .monaco-findInput > .controls .monaco-custom-checkbox::before, -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-up::before, -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-down::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .search-view .query-details .file-types .controls > .monaco-custom-checkbox.useExcludesAndIgnoreFiles::before, -body[data-exploration^="icon-exploration"] .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude::before { - content: ""; - width: 16px; - height: 16px; - display: block; -} - -/******************** - ACTIVITY BAR -********************/ - -body[data-exploration^="icon-exploration"] .monaco-workbench .activitybar > .content .monaco-action-bar .badge .badge-content { - font-size: 9px; - font-weight: 600; - height: 16px; - line-height: 16px; - padding: 0 4px; -} - -body[data-exploration^="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label { - -webkit-mask-size: 24px !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.explore { - -webkit-mask-image: url("images/activitybar/files-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.search { - -webkit-mask-image: url("images/activitybar/search-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.scm { - -webkit-mask-image: url("images/activitybar/git-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.debug { - -webkit-mask-image: url("images/activitybar/debug-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.extensions { - -webkit-mask-image: url("images/activitybar/extensions-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar .monaco-action-bar .action-label.update-activity { - -webkit-mask-image: url("images/activitybar/settings-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .activitybar > .content > .composite-bar > .monaco-action-bar .action-label.toggle-more { - -webkit-mask-image: url("images/activitybar/more-alt1.svg"); -} - - -/**************** - Explorer -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .flip-editor-layout { - -webkit-mask-image: url("images/explorer/layout-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-action.save-all, -body[data-exploration="icon-exploration"] .monaco-workbench .save-all { - -webkit-mask-image: url("images/explorer/save-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-viewlet .action-close-all-files { - -webkit-mask-image: url("images/explorer/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-action.new-file { - -webkit-mask-image: url("images/explorer/add-file-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-action.new-folder { - -webkit-mask-image: url("images/explorer/add-folder-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-action.refresh-explorer { - -webkit-mask-image: url("images/explorer/refresh-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-action.collapse-explorer { - -webkit-mask-image: url("images/explorer/collapse-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-toolbar .action-label.toolbar-toggle-more { - -webkit-mask-image: url("images/explorer/more-alt1.svg"); -} - - -/**************** - Search -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .search-action.refresh { - -webkit-mask-image: url("images/search/refresh-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .search-action.clear-search-results { - -webkit-mask-image: url("images/search/clear-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .search-action.collapse { - -webkit-mask-image: url("images/search/collapse-all-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .search-action.cancel-search { - -webkit-mask-image: url("images/search/stop-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .search-widget .replace-container .monaco-action-bar .action-item .icon { - -webkit-mask-image: url("images/search/replace-all-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .search-view .query-details .file-types .controls > .monaco-custom-checkbox.useExcludesAndIgnoreFiles::before, -body[data-exploration="icon-exploration"] .markers-panel-action-filter > .markers-panel-filter-controls > .markers-panel-filter-filesExclude::before { - -webkit-mask-image: url("images/search/exclude-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-custom-checkbox.monaco-case-sensitive::before { - -webkit-mask-image: url("images/search/case-sensitive-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-custom-checkbox.monaco-whole-word::before { - -webkit-mask-image: url("images/search/whole-word-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-custom-checkbox.monaco-regex::before { - -webkit-mask-image: url("images/search/regex-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .action-replace { - -webkit-mask-image: url("images/search/replace-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .action-replace-all { - -webkit-mask-image: url("images/search/replace-all-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .action-remove { - -webkit-mask-image: url("images/search/remove-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .search-view .query-details .more { - -webkit-mask-image: url("images/search/more-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .search-widget .toggle-replace-button.collapse::before { - -webkit-mask-image: url("images/search/collapse-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .search-view .search-widget .toggle-replace-button.expand::before { - -webkit-mask-image: url("images/search/expand-alt1.svg"); -} - - -/**************** - Git -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="git.init"] { - -webkit-mask-image: url("images/git/initialze.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="git.commit"], -body[data-exploration="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.icon[data-title="git.commit"] { - -webkit-mask-image: url("images/git/check-alt1.svg"); -} -/* Refresh */ -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="git.refresh"], -body[data-exploration="icon-exploration"] .monaco-panel-view .panel > .panel-header > .actions .action-label.icon[data-title="git.refresh"] { - -webkit-mask-image: url("images/git/refresh-alt1.svg"); -} -/* Stage */ -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="git.stageChange"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.stageAll"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title="git.stage"] { - -webkit-mask-image: url("images/git/stage-alt1.svg"); -} -/* Unstage */ -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.unstageAll"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title="git.unstage"] { - -webkit-mask-image: url("images/git/unstage-alt1.svg"); -} -/* Discard */ -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="git.revertChange"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource-group > .actions .action-label[data-title="git.cleanAll"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title="git.clean"] { - -webkit-mask-image: url("images/git/clean-alt1.svg"); -} -/* Open File */ -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="_workbench.openUserSettingsEditor"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="git.openFile"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="git.openFile"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.openGlobalKeybindings"], -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title="git.openFile2"] { - -webkit-mask-image: url("images/git/gotofile-alt1.svg"); -} -/* Chevrons */ -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.compareEditor.nextChange"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.compareEditor.nextChange"], -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="editor.action.marker.next"], -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="editor.action.dirtydiff.next"] { - -webkit-mask-image: url("images/git/next-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.compareEditor.previousChange"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.compareEditor.previousChange"], -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="editor.action.marker.prev"], -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions > .monaco-action-bar .action-label[data-title="editor.action.dirtydiff.previous"] { - -webkit-mask-image: url("images/git/previous-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="toggle.diff.ignoreTrimWhitespace"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="toggle.diff.ignoreTrimWhitespace"]{ - -webkit-mask-image: url("images/git/whitespace-alt1.svg"); -} - - -/**************** - Debug -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-action.start, -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.continue"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .start-debug-action-item .icon { - -webkit-mask-image: url("images/debug/start-alt1.svg"); - background: var(--green) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-action.configure { - -webkit-mask-image: url("images/debug/gear-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-action.toggle-repl { - -webkit-mask-image: url("images/debug/repl-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-viewlet .debug-action.add-watch-expression, -body[data-exploration="icon-exploration"] .debug-viewlet .debug-action.add-function-breakpoint { - -webkit-mask-image: url("images/debug/add-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-viewlet .debug-action.remove-all { - -webkit-mask-image: url("images/debug/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-viewlet .debug-action.breakpoints-activate { - -webkit-mask-image: url("images/debug/breakpoint-activate-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .drag-area { - -webkit-mask-image: url("images/debug/drag-alt1.svg"); - background: var(--grayLight); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.stepOver"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.stepOver"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.stepBack"], -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.stepBack"] { - -webkit-mask-image: url("images/debug/step-over-alt1.svg"); - background: var(--blue) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.stepInto"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.stepInto"] { - -webkit-mask-image: url("images/debug/step-into-alt1.svg"); - background: var(--blue) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.stepOut"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.stepOut"] { - -webkit-mask-image: url("images/debug/step-out-alt1.svg"); - background: var(--blue) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.continue"], -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.rever"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.continue"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.rever"] { - -webkit-mask-image: url("images/debug/continue-alt1.svg"); - background: var(--blue) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.restart"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.restart"] { - -webkit-mask-image: url("images/debug/restart-alt1.svg"); - background: var(--green) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.pause"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.pause"] { - -webkit-mask-image: url("images/debug/pause-alt1.svg"); - background: var(--green) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.stop"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.stop"] { - -webkit-mask-image: url("images/debug/stop-alt1.svg"); - background: var(--red) !important; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .debug-toolbar .action-label[data-title="workbench.action.debug.disconnect"], -body[data-exploration="icon-exploration"] .monaco-workbench .part > .title > .title-actions .action-label[data-title="workbench.action.debug.disconnect"] { - -webkit-mask-image: url("images/debug/disconnect-alt1.svg"); - background: var(--red) !important; -} - -body[data-exploration="icon-exploration"] .debug-breakpoint, -body[data-exploration="icon-exploration"] .debug-breakpoint-hint, -body[data-exploration="icon-exploration"] .debug-breakpoint.icon, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-column::before { - -webkit-mask-image: url("images/debug/breakpoint-alt1.svg"); - background: var(--redLight) !important; -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-hint:not(.debug-breakpoint):not(.debug-breakpoint-conditional):not(.debug-top-stack-frame):not(.debug-focused-stack-frame):not(.debug-breakpoint-log) { - opacity: .5 !important; -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-disabled.icon { - -webkit-mask-image: url("images/debug/breakpoint-unverified-alt1.svg"); - background: var(--grayLight); -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-unverified, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-column.debug-breakpoint-disabled-column::before { - -webkit-mask-image: url("images/debug/breakpoint-alt1.svg"); - background: var(--grayLight); -} - -body[data-exploration="icon-exploration"] .monaco-editor .debug-top-stack-frame-column::before, -body[data-exploration="icon-exploration"] .monaco-editor .debug-top-stack-frame { - -webkit-mask-image: url("images/debug/current-arrow-alt1.svg"); - background: var(--yellow) !important; -} - -body[data-exploration="icon-exploration"] .monaco-editor .debug-top-stack-frame.debug-breakpoint, -body[data-exploration="icon-exploration"] .monaco-editor .debug-top-stack-frame.debug-breakpoint-conditional, -body[data-exploration="icon-exploration"] .monaco-editor .debug-top-stack-frame.debug-breakpoint-log, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-column.debug-breakpoint-column.debug-top-stack-frame-column::before { - -webkit-mask-image: url("images/debug/current-and-breakpoint-alt1.svg"); - background: var(--yellow) !important; -} - -body[data-exploration="icon-exploration"] .monaco-editor .debug-focused-stack-frame.debug-breakpoint, -body[data-exploration="icon-exploration"] .monaco-editor .debug-focused-stack-frame.debug-breakpoint-conditional, -body[data-exploration="icon-exploration"] .monaco-editor .debug-focused-stack-frame.debug-breakpoint-log { - -webkit-mask-image: url("images/debug/stackframe-and-breakpoint-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-log, -body[data-exploration="icon-exploration"] .debug-breakpoint-log.icon, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-column.debug-breakpoint-log-column::before { - -webkit-mask-image: url("images/debug/breakpoint-log-alt1.svg"); - background: var(--redLight) !important; -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-log-disabled, -body[data-exploration="icon-exploration"] .debug-breakpoint-log-disabled.icon, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-log-disabled-column::before { - -webkit-mask-image: url("images/debug/breakpoint-log-alt1.svg"); - background: var(--grayLight); -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-log-unverified, -body[data-exploration="icon-exploration"] .debug-breakpoint-log-unverified.icon, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-log-unverified-column::before { - -webkit-mask-image: url("images/debug/breakpoint-log-unverified-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-breakpoint-conditional, -body[data-exploration="icon-exploration"] .debug-breakpoint-conditional.icon, -body[data-exploration="icon-exploration"] .monaco-editor .debug-breakpoint-column.debug-breakpoint-conditional-column::before { - -webkit-mask-image: url("images/debug/breakpoint-conditional-alt1.svg"); - background: var(--redLight) !important; -} - -body[data-exploration="icon-exploration"] .monaco-editor .debug-focused-stack-frame { - -webkit-mask-image: url("images/debug/stackframe-arrow-alt1.svg"); - background: var(--green) !important; -} - -body[data-exploration="icon-exploration"] .debug-function-breakpoint, -body[data-exploration="icon-exploration"] .debug-function-breakpoint.icon { - -webkit-mask-image: url("images/debug/breakpoint-function-alt1.svg"); - background: var(--redLight) !important; -} - -body[data-exploration="icon-exploration"] .debug-function-breakpoint-unverified { - -webkit-mask-image: url("images/debug/breakpoint-function-unverified-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-function-breakpoint-disabled { - -webkit-mask-image: url("images/debug/breakpoint-function-disabled-alt1.svg"); -} - -/**************** - Extensions -****************/ - -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header { - align-items: center; -} - -body[data-exploration="icon-exploration"] .monaco-action-bar .action-item .action-label.clear-extensions { - -webkit-mask-image: url("images/extensions/clear-alt1.svg"); -} - -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count:not(:empty), -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .ratings { - display: flex; - align-items: center; - justify-content: center; -} - -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon::before, -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle .octicon::before { - content: "" !important; -} - -body[data-exploration^="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon, -body[data-exploration^="icon-exploration"] .extension-ratings.small > .full { - width: 12px; - height: 12px; - -webkit-mask-size: 12px; -} - -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle .octicon { - width: 16px; - height: 16px; - -webkit-mask-size: 16px; -} - -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle > span:not(:first-child):not(:empty) { - position: relative; -} - -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle > .install > .count { - margin-left: 22px; -} - -body[data-exploration^="icon-exploration"] .extension-editor > .header > .details > .subtitle .octicon { - position: absolute; - left: 14px; - top: 0; -} - -body[data-exploration="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .header-container > .header > .install-count > .octicon, -body[data-exploration="icon-exploration"] .extension-editor > .header > .details > .subtitle .octicon { - -webkit-mask-image: url("images/extensions/download-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .extension-ratings > .full { - -webkit-mask-image: url("images/extensions/star-full-alt1.svg"); - background: var(--orangeLight); -} - -body[data-exploration="icon-exploration"] .extension-ratings > .half { - -webkit-mask-image: url("images/extensions/star-half-alt1.svg"); - background: var(--orangeLight); -} - -body[data-exploration="icon-exploration"] .extension-ratings > .empty { - -webkit-mask-image: url("images/extensions/star-empty-alt1.svg"); - background: var(--gray); -} - -body[data-exploration="icon-exploration"] .extensions-viewlet > .extensions .extension > .details > .footer > .monaco-action-bar .action-item .action-label.extension-action.manage { - -webkit-mask-image: url("images/extensions/gear-alt1.svg"); -} - - -/**************** - Panels -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .hide-panel-action, -.hc-black .monaco-workbench .hide-panel-action { - -webkit-mask-image: url("images/panel/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .maximize-panel-action { - -webkit-mask-image: url("images/panel/up-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .minimize-panel-action { - -webkit-mask-image: url("images/panel/down-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-tree-action.collapse-all { - -webkit-mask-image: url("images/panel/collapse-all-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .output-action.open-log-file { - -webkit-mask-image: url("images/panel/gotofile-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .output-action.open-log-file { - -webkit-mask-image: url("images/panel/gotofile-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .output-action.output-scroll-unlock { - -webkit-mask-image: url("images/panel/output-unlock-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .output-action.output-scroll-lock { - -webkit-mask-image: url("images/panel/output-lock-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .output-action.clear-output { - -webkit-mask-image: url("images/panel/clear-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .debug-action.clear-repl { - -webkit-mask-image: url("images/panel/clear-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .terminal-action.kill { - -webkit-mask-image: url("images/panel/kill-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .terminal-action.split, -body[data-exploration="icon-exploration"] .monaco-workbench .quick-open-sidebyside-vertical { - -webkit-mask-image: url("images/panel/split-horizontal-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .panel.right .terminal-action.split { - -webkit-mask-image: url("images/panel/split-vertical-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .terminal-action.new { - -webkit-mask-image: url("images/panel/add-alt1.svg"); -} - - -/**************** - IntelliSense -****************/ - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .details > .monaco-scrollable-element > .body > .header > .close { - -webkit-mask-image: url("images/intellisense/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row > .contents > .main > .readMore { - -webkit-mask-image: url("images/intellisense/info-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon::before { - background-image: none !important; -} -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.method::before, -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.function::before, -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constructor::before { - -webkit-mask-image: url("images/intellisense/method-alt1.svg"); - background-color: var(--purple); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.field::before { - -webkit-mask-image: url("images/intellisense/field-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.event::before { - -webkit-mask-image: url("images/intellisense/event-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.operator::before { - -webkit-mask-image: url("images/intellisense/operator-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.variable::before { - -webkit-mask-image: url("images/intellisense/variable-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.class::before { - -webkit-mask-image: url("images/intellisense/class-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.interface::before { - -webkit-mask-image: url("images/intellisense/interface-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.struct::before { - -webkit-mask-image: url("images/intellisense/structure-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.type-parameter::before { - -webkit-mask-image: url("images/intellisense/parameter-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.module::before { - -webkit-mask-image: url("images/intellisense/namespace-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.property::before { - -webkit-mask-image: url("images/intellisense/property-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.unit::before { - -webkit-mask-image: url("images/intellisense/ruler-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.constant::before { - -webkit-mask-image: url("images/intellisense/constant-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.value::before, -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum::before { - -webkit-mask-image: url("images/intellisense/enumerator-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.enum-member::before { - -webkit-mask-image: url("images/intellisense/enum-member-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.keyword::before { - -webkit-mask-image: url("images/intellisense/keyword-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.text::before { - -webkit-mask-image: url("images/intellisense/string-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.color::before { - -webkit-mask-image: url("images/intellisense/color-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.file::before { - -webkit-mask-image: url("images/intellisense/file-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.reference::before { - -webkit-mask-image: url("images/intellisense/reference-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.snippet::before { - -webkit-mask-image: url("images/intellisense/snippet-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .suggest-widget .monaco-list .monaco-list-row .suggest-icon.folder::before { - -webkit-mask-image: url("images/intellisense/folder-alt1.svg"); -} - -/**************** - Breadcrumbs -****************/ - -body[data-exploration^="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title.breadcrumbs .breadcrumbs-control .monaco-breadcrumb-item::before { - -webkit-mask-image: none; - background: transparent; -} - -body[data-exploration^="icon-exploration"] .monaco-quick-open-widget .quick-open-tree .quick-open-entry .quick-open-entry-icon::before { - left: 0; - top: -3px; -} - -body[data-exploration^="icon-exploration"] .monaco-workbench .breadcrumbs-control .symbol-icon::before, -body[data-exploration^="icon-exploration"] .monaco-workbench .monaco-breadcrumb-item .symbol-icon { - top: -2px; -} - -body[data-exploration^="icon-exploration"] .monaco-workbench .symbol-icon { - position: relative; - background-image: none !important; - -webkit-mask-position: left center; -} - -body[data-exploration^="icon-exploration"] .monaco-workbench .symbol-icon::before { - content: ""; - position: absolute; - left: -3px; - width: 16px; - height: 22px; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon::before { - -webkit-mask-image: url("images/intellisense/field-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.constant::before { - -webkit-mask-image: url("images/intellisense/constant-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.enum::before { - -webkit-mask-image: url("images/intellisense/enumerator-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.enum-member::before { - -webkit-mask-image: url("images/intellisense/enum-member-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.struct::before { - -webkit-mask-image: url("images/intellisense/structure-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.event::before { - -webkit-mask-image: url("images/intellisense/event-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.operator::before { - -webkit-mask-image: url("images/intellisense/operator-alt1.svg"); - background-color: var(--blue); -} - -ody[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.type-parameter::before { - -webkit-mask-image: url("images/intellisense/parameter-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.boolean::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.null::before { - -webkit-mask-image: url("images/intellisense/boolean-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.class::before { - -webkit-mask-image: url("images/intellisense/class-alt1.svg"); - background-color: var(--orange); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.constructor::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.method::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.function::before { - -webkit-mask-image: url("images/intellisense/method-alt1.svg"); - background-color: var(--purple); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.file::before { - -webkit-mask-image: url("images/intellisense/file-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.field::before { - -webkit-mask-image: url("images/intellisense/field-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.variable::before { - -webkit-mask-image: url("images/intellisense/variable-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.array::before { - -webkit-mask-image: url("images/intellisense/array-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.keyword::before { - -webkit-mask-image: url("images/intellisense/keyword-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.interface::before { - -webkit-mask-image: url("images/intellisense/interface-alt1.svg"); - background-color: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.object::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.namespace::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.package::before, -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.module::before { - -webkit-mask-image: url("images/intellisense/namespace-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.number::before { - -webkit-mask-image: url("images/intellisense/numeric-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.property::before { - -webkit-mask-image: url("images/intellisense/property-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.string::before { - -webkit-mask-image: url("images/intellisense/key-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .symbol-icon.key::before { - -webkit-mask-image: url("images/intellisense/key-alt1.svg"); -} - -body[data-exploration^="icon-exploration"] .monaco-editor .lightbulb-glyph { - background-image: none !important; - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center center; - -webkit-mask-size: 16px; -} - -body[data-exploration="icon-exploration"] .monaco-editor .lightbulb-glyph, -body[data-exploration="icon-exploration"] .markers-panel .monaco-tl-contents .actions .action-label.icon.markers-panel-action-quickfix { - -webkit-mask-image: url("images/intellisense/lightbulb-alt1.svg"); - background-color: var(--yellow); -} - -body[data-exploration="icon-exploration"] .monaco-editor .lightbulb-glyph.autofixable, -body[data-exploration="icon-exploration"] .markers-panel .monaco-tl-contents .actions .action-label.icon.markers-panel-action-quickfix.autofixable { - -webkit-mask-image: url("images/intellisense/lightbulb-autofix-alt1.svg"); - background-color: var(--blue); -} - - -/**************** - Notifications -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-icon.icon-info, -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .severity-icon.severity-info, -body[data-exploration="icon-exploration"] .markers-panel .marker-icon.severity-info { - -webkit-mask-image: url("images/notifications/info-alt1.svg"); - background: var(--blue); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-icon.icon-warning, -body[data-exploration="icon-exploration"] .markers-panel .marker-icon.severity-warning, -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .severity-icon.severity-warning { - -webkit-mask-image: url("images/notifications/warning-alt1.svg"); - background: var(--yellow); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-icon.icon-error, -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-title .severity-icon.severity-error, -body[data-exploration="icon-exploration"] .markers-panel .marker-icon.severity-error { - -webkit-mask-image: url("images/notifications/error-alt1.svg"); - background: var(--redLight); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .clear-notification-action { - -webkit-mask-image: url("images/notifications/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .expand-notification-action { - -webkit-mask-image: url("images/notifications/up-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .collapse-notification-action { - -webkit-mask-image: url("images/notifications/down-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .notifications-list-container .notification-list-item .notification-list-item-toolbar-container .configure-notification-action { - -webkit-mask-image: url("images/notifications/configure-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench > .notifications-center > .notifications-center-header .clear-all-notifications-action { - -webkit-mask-image: url("images/notifications/closeall-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench > .notifications-center > .notifications-center-header .hide-all-notifications-action { - -webkit-mask-image: url("images/notifications/down-alt1.svg"); -} - -body[data-exploration^="icon-exploration"] .markers-panel .monaco-tl-contents .marker-icon { - min-width: 16px; -} - - -/**************** - Tree -****************/ - -body[data-exploration^="icon-exploration"] .monaco-panel-view .panel > .panel-header::before { - position: absolute; - left: 2px; - top: 2px; -} - -body[data-exploration="icon-exploration"] .file-icon-themable-tree .monaco-tree-row.has-children.expanded .content::before, -body[data-exploration="icon-exploration"] .monaco-panel-view .panel > .panel-header.expanded::before, -body[data-exploration="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-up, -body[data-exploration="icon-exploration"] .monaco-tl-twistie.collapsible:not(.loading) { - -webkit-mask-image: url("images/tree/expand-alt1.svg"); - background-image: url("images/tree/expand-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .file-icon-themable-tree .monaco-tree-row.has-children .content::before, -body[data-exploration="icon-exploration"] .monaco-breadcrumbs .monaco-breadcrumb-item:not(:nth-child(2))::before, -body[data-exploration="icon-exploration"] .monaco-panel-view .panel > .panel-header::before, -body[data-exploration="icon-exploration"] .markers-panel .monaco-tl-contents .multiline-actions .action-label.octicon-chevron-down, -body[data-exploration="icon-exploration"] .monaco-tl-twistie.collapsible.collapsed:not(.loading) { - -webkit-mask-image: url("images/tree/collapse-alt1.svg"); - background-image: url("images/tree/collapse-alt1.svg"); - -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.closeActiveEditor"], -body[data-exploration="icon-exploration"] .monaco-editor .peekview-widget .head .peekview-actions .action-label.icon[data-title="peekview.close"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .close-editor-action, -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action:hover, -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .editor-group-container-toolbar .close-editor-group, -body[data-exploration="icon-exploration"] .monaco-workbench .explorer-viewlet .explorer-open-editors .close-editor-action { - -webkit-mask-image: url("images/tree/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.dirty .close-editor-action, -body[data-exploration="icon-exploration"] .explorer-viewlet .explorer-open-editors .monaco-list .monaco-list-row.dirty:not(:hover) > .monaco-action-bar .close-editor-action { - -webkit-mask-image: url("images/tree/dirty-alt1.svg"); -} - - -/**************** - Tree -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="workbench.action.splitEditor"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.splitEditor"] { - -webkit-mask-image: url("images/editor/split-horizontal-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[title="Split Editor Down"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[title="Split Editor Down"] { - -webkit-mask-image: url("images/editor/split-vertical-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .scm-viewlet .monaco-list-row > .resource > .name > .monaco-icon-label > .actions .action-label[data-title="git.openChange"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .title-actions .action-label[data-title="git.openChange"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="git.openChange"] { - -webkit-mask-image: url("images/editor/open-change-alt1.svg"); -} - - -/**************** - Find -****************/ - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .previous::before { - -webkit-mask-image: url("images/find/previous-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .next::before { - -webkit-mask-image: url("images/find/next-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .close-fw::before { - -webkit-mask-image: url("images/find/close-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .monaco-checkbox .label::before { - -webkit-mask-image: url("images/find/selection-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .replace::before { - -webkit-mask-image: url("images/find/replace-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .replace-all::before { - -webkit-mask-image: url("images/find/replace-all-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .expand::before { - -webkit-mask-image: url("images/find/expand-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .find-widget .collapse::before { - -webkit-mask-image: url("images/find/collapse-alt1.svg"); -} - -/**************** - Misc -****************/ - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="markdown.showPreviewToSide"]{ - -webkit-mask-image: url("images/misc/preview-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit .monaco-icon-label.file-icon[title^="Preview"]::before{ - -webkit-mask-image: url("images/misc/preview-icon-alt1.svg"); - -webkit-mask-position: left center; -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="markdown.showSource"]{ - -webkit-mask-image: url("images/misc/gotofile-alt1.svg") -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="workbench.action.openGlobalKeybindingsFile"], -body[data-exploration="icon-exploration"] .monaco-workbench .part.editor > .content .editor-group-container > .title .editor-actions .action-label[data-title="settings.switchToJSON"]{ - -webkit-mask-image: url("images/misc/json-alt1.svg") -} - -body[data-exploration^="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .monaco-custom-checkbox::before { - display: block; -} - -body[data-exploration="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .record-keys::before { - -webkit-mask-image: url("images/misc/keyboard-alt1.svg") -} - -body[data-exploration="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .clear-input { - -webkit-mask-image: url("images/misc/clear-alt1.svg") -} - -body[data-exploration="icon-exploration"] .keybindings-editor .monaco-action-bar .action-item > .sort-by-precedence::before { - -webkit-mask-image: url("images/misc/precedence-alt1.svg") -} - -body[data-exploration="icon-exploration"] .monaco-workbench .part.panel > .title > .panel-switcher-container.composite-bar > .monaco-action-bar .action-label.toggle-more { - -webkit-mask-image: url("images/misc/more-alt1.svg"); - background: var(--gray) !important; -} - -body[data-exploration^="icon-exploration"] .monaco-editor .margin-view-overlays .folding, -body[data-exploration^="icon-exploration"] .monaco-editor .margin-view-overlays .folding.collapsed { - -webkit-mask-position: 75% 50%; -} - -body[data-exploration="icon-exploration"] .monaco-editor .margin-view-overlays .folding { - -webkit-mask-image: url("images/misc/fold-alt1.svg"); -} - -body[data-exploration="icon-exploration"] .monaco-editor .margin-view-overlays .folding.collapsed { - -webkit-mask-image: url("images/misc/unfold-alt1.svg"); -} \ No newline at end of file diff --git a/src/vs/workbench/browser/media/images/activitybar/debug-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/debug-alt1.svg deleted file mode 100644 index dfe350a283..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/debug-alt1.svg +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/extensions-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/extensions-alt1.svg deleted file mode 100644 index 3fd6c5b9ca..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/extensions-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/files-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/files-alt1.svg deleted file mode 100644 index f2ddfd97b7..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/files-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/git-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/git-alt1.svg deleted file mode 100644 index 6ce8a7c1c5..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/git-alt1.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/more-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/more-alt1.svg deleted file mode 100644 index 6729ca3c90..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/more-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/search-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/search-alt1.svg deleted file mode 100644 index fb1a6e7bd5..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/search-alt1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/activitybar/settings-alt1.svg b/src/vs/workbench/browser/media/images/activitybar/settings-alt1.svg deleted file mode 100644 index b2a6110211..0000000000 --- a/src/vs/workbench/browser/media/images/activitybar/settings-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/add-alt1.svg b/src/vs/workbench/browser/media/images/debug/add-alt1.svg deleted file mode 100644 index fb50c6c284..0000000000 --- a/src/vs/workbench/browser/media/images/debug/add-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-activate-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-activate-alt1.svg deleted file mode 100644 index 3e6b0a4c4d..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-activate-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-alt1.svg deleted file mode 100644 index e391c3b085..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-conditional-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-conditional-alt1.svg deleted file mode 100644 index 9794d6b552..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-conditional-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-function-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-function-alt1.svg deleted file mode 100644 index 76d1f05da2..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-function-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-function-disabled-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-function-disabled-alt1.svg deleted file mode 100644 index 76d1f05da2..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-function-disabled-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-function-unverified-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-function-unverified-alt1.svg deleted file mode 100644 index ece98d0f35..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-function-unverified-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-log-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-log-alt1.svg deleted file mode 100644 index 21ada7b292..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-log-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-log-unverified-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-log-unverified-alt1.svg deleted file mode 100644 index f540bf94ef..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-log-unverified-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/breakpoint-unverified-alt1.svg b/src/vs/workbench/browser/media/images/debug/breakpoint-unverified-alt1.svg deleted file mode 100644 index 6bfa8fd2f5..0000000000 --- a/src/vs/workbench/browser/media/images/debug/breakpoint-unverified-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/close-alt1.svg b/src/vs/workbench/browser/media/images/debug/close-alt1.svg deleted file mode 100644 index 8af24a5b1e..0000000000 --- a/src/vs/workbench/browser/media/images/debug/close-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/continue-alt1.svg b/src/vs/workbench/browser/media/images/debug/continue-alt1.svg deleted file mode 100644 index d9e1bcfa25..0000000000 --- a/src/vs/workbench/browser/media/images/debug/continue-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/debug/current-and-breakpoint-alt1.svg b/src/vs/workbench/browser/media/images/debug/current-and-breakpoint-alt1.svg deleted file mode 100644 index df3c2501a5..0000000000 --- a/src/vs/workbench/browser/media/images/debug/current-and-breakpoint-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/debug/current-arrow-alt1.svg b/src/vs/workbench/browser/media/images/debug/current-arrow-alt1.svg deleted file mode 100644 index f62a9fb6db..0000000000 --- a/src/vs/workbench/browser/media/images/debug/current-arrow-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/disconnect-alt1.svg b/src/vs/workbench/browser/media/images/debug/disconnect-alt1.svg deleted file mode 100644 index 71aae0dd88..0000000000 --- a/src/vs/workbench/browser/media/images/debug/disconnect-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/drag-alt1.svg b/src/vs/workbench/browser/media/images/debug/drag-alt1.svg deleted file mode 100644 index b6b93f31fd..0000000000 --- a/src/vs/workbench/browser/media/images/debug/drag-alt1.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/gear-alt1.svg b/src/vs/workbench/browser/media/images/debug/gear-alt1.svg deleted file mode 100644 index 7db1664af7..0000000000 --- a/src/vs/workbench/browser/media/images/debug/gear-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/debug/pause-alt1.svg b/src/vs/workbench/browser/media/images/debug/pause-alt1.svg deleted file mode 100644 index 1050e04f2d..0000000000 --- a/src/vs/workbench/browser/media/images/debug/pause-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/repl-alt1.svg b/src/vs/workbench/browser/media/images/debug/repl-alt1.svg deleted file mode 100644 index f13e57b89a..0000000000 --- a/src/vs/workbench/browser/media/images/debug/repl-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/restart-alt1.svg b/src/vs/workbench/browser/media/images/debug/restart-alt1.svg deleted file mode 100644 index 28c63aae4d..0000000000 --- a/src/vs/workbench/browser/media/images/debug/restart-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/stackframe-and-breakpoint-alt1.svg b/src/vs/workbench/browser/media/images/debug/stackframe-and-breakpoint-alt1.svg deleted file mode 100644 index df3c2501a5..0000000000 --- a/src/vs/workbench/browser/media/images/debug/stackframe-and-breakpoint-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/debug/stackframe-arrow-alt1.svg b/src/vs/workbench/browser/media/images/debug/stackframe-arrow-alt1.svg deleted file mode 100644 index f62a9fb6db..0000000000 --- a/src/vs/workbench/browser/media/images/debug/stackframe-arrow-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/start-alt1.svg b/src/vs/workbench/browser/media/images/debug/start-alt1.svg deleted file mode 100644 index 30196ede16..0000000000 --- a/src/vs/workbench/browser/media/images/debug/start-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/debug/step-into-alt1.svg b/src/vs/workbench/browser/media/images/debug/step-into-alt1.svg deleted file mode 100644 index 2113d7b198..0000000000 --- a/src/vs/workbench/browser/media/images/debug/step-into-alt1.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/step-out-alt1.svg b/src/vs/workbench/browser/media/images/debug/step-out-alt1.svg deleted file mode 100644 index 6724964aea..0000000000 --- a/src/vs/workbench/browser/media/images/debug/step-out-alt1.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/step-over-alt1.svg b/src/vs/workbench/browser/media/images/debug/step-over-alt1.svg deleted file mode 100644 index f2454843ae..0000000000 --- a/src/vs/workbench/browser/media/images/debug/step-over-alt1.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/debug/stop-alt1.svg b/src/vs/workbench/browser/media/images/debug/stop-alt1.svg deleted file mode 100644 index 4e348228b6..0000000000 --- a/src/vs/workbench/browser/media/images/debug/stop-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/editor/open-change-alt1.svg b/src/vs/workbench/browser/media/images/editor/open-change-alt1.svg deleted file mode 100644 index 0c8297f940..0000000000 --- a/src/vs/workbench/browser/media/images/editor/open-change-alt1.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/editor/split-horizontal-alt1.svg b/src/vs/workbench/browser/media/images/editor/split-horizontal-alt1.svg deleted file mode 100644 index c92025ddd9..0000000000 --- a/src/vs/workbench/browser/media/images/editor/split-horizontal-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/editor/split-vertical-alt1.svg b/src/vs/workbench/browser/media/images/editor/split-vertical-alt1.svg deleted file mode 100644 index f407c08fa3..0000000000 --- a/src/vs/workbench/browser/media/images/editor/split-vertical-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/add-file-alt1.svg b/src/vs/workbench/browser/media/images/explorer/add-file-alt1.svg deleted file mode 100644 index 138351f66b..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/add-file-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/add-folder-alt1.svg b/src/vs/workbench/browser/media/images/explorer/add-folder-alt1.svg deleted file mode 100644 index 0f1a2bfb9b..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/add-folder-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/close-alt1.svg b/src/vs/workbench/browser/media/images/explorer/close-alt1.svg deleted file mode 100644 index 8af24a5b1e..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/close-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/collapse-alt1.svg b/src/vs/workbench/browser/media/images/explorer/collapse-alt1.svg deleted file mode 100644 index f2e0e5dd5f..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/collapse-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/layout-alt1.svg b/src/vs/workbench/browser/media/images/explorer/layout-alt1.svg deleted file mode 100644 index 40c1b46b19..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/layout-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/explorer/more-alt1.svg b/src/vs/workbench/browser/media/images/explorer/more-alt1.svg deleted file mode 100644 index 3d7068f6b4..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/more-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/explorer/refresh-alt1.svg b/src/vs/workbench/browser/media/images/explorer/refresh-alt1.svg deleted file mode 100644 index a940b8ef4a..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/refresh-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/explorer/save-alt1.svg b/src/vs/workbench/browser/media/images/explorer/save-alt1.svg deleted file mode 100644 index 5756795cb4..0000000000 --- a/src/vs/workbench/browser/media/images/explorer/save-alt1.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/clear-alt1.svg b/src/vs/workbench/browser/media/images/extensions/clear-alt1.svg deleted file mode 100644 index 63be0fae21..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/clear-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/download-alt1.svg b/src/vs/workbench/browser/media/images/extensions/download-alt1.svg deleted file mode 100644 index 211864d2c8..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/download-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/gear-alt1.svg b/src/vs/workbench/browser/media/images/extensions/gear-alt1.svg deleted file mode 100644 index 7db1664af7..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/gear-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/star-empty-alt1.svg b/src/vs/workbench/browser/media/images/extensions/star-empty-alt1.svg deleted file mode 100644 index a35ded971f..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/star-empty-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/star-full-alt1.svg b/src/vs/workbench/browser/media/images/extensions/star-full-alt1.svg deleted file mode 100644 index 2413e6ecb1..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/star-full-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/extensions/star-half-alt1.svg b/src/vs/workbench/browser/media/images/extensions/star-half-alt1.svg deleted file mode 100644 index 4e8dcd71f3..0000000000 --- a/src/vs/workbench/browser/media/images/extensions/star-half-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/find/close-alt1.svg b/src/vs/workbench/browser/media/images/find/close-alt1.svg deleted file mode 100644 index 2512e9d61a..0000000000 --- a/src/vs/workbench/browser/media/images/find/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/find/collapse-alt1.svg b/src/vs/workbench/browser/media/images/find/collapse-alt1.svg deleted file mode 100644 index 6d01adc07e..0000000000 --- a/src/vs/workbench/browser/media/images/find/collapse-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/find/expand-alt1.svg b/src/vs/workbench/browser/media/images/find/expand-alt1.svg deleted file mode 100644 index a1a96a6092..0000000000 --- a/src/vs/workbench/browser/media/images/find/expand-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/find/next-alt1.svg b/src/vs/workbench/browser/media/images/find/next-alt1.svg deleted file mode 100644 index d2660e6e90..0000000000 --- a/src/vs/workbench/browser/media/images/find/next-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/find/previous-alt1.svg b/src/vs/workbench/browser/media/images/find/previous-alt1.svg deleted file mode 100644 index 6f8d0cbcb6..0000000000 --- a/src/vs/workbench/browser/media/images/find/previous-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/find/replace-all-alt1.svg b/src/vs/workbench/browser/media/images/find/replace-all-alt1.svg deleted file mode 100644 index 66437cf441..0000000000 --- a/src/vs/workbench/browser/media/images/find/replace-all-alt1.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/find/replace-alt1.svg b/src/vs/workbench/browser/media/images/find/replace-alt1.svg deleted file mode 100644 index b599b6e543..0000000000 --- a/src/vs/workbench/browser/media/images/find/replace-alt1.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/browser/media/images/find/selection-alt1.svg b/src/vs/workbench/browser/media/images/find/selection-alt1.svg deleted file mode 100644 index e0503a93a5..0000000000 --- a/src/vs/workbench/browser/media/images/find/selection-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/check-alt1.svg b/src/vs/workbench/browser/media/images/git/check-alt1.svg deleted file mode 100644 index a5597d7c40..0000000000 --- a/src/vs/workbench/browser/media/images/git/check-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/clean-alt1.svg b/src/vs/workbench/browser/media/images/git/clean-alt1.svg deleted file mode 100644 index 2f3dd525c0..0000000000 --- a/src/vs/workbench/browser/media/images/git/clean-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/close-alt1.svg b/src/vs/workbench/browser/media/images/git/close-alt1.svg deleted file mode 100644 index 64618b6176..0000000000 --- a/src/vs/workbench/browser/media/images/git/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/git/gotofile-alt1.svg b/src/vs/workbench/browser/media/images/git/gotofile-alt1.svg deleted file mode 100644 index aabfc34c3e..0000000000 --- a/src/vs/workbench/browser/media/images/git/gotofile-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/git/initialze.svg b/src/vs/workbench/browser/media/images/git/initialze.svg deleted file mode 100644 index fb50c6c284..0000000000 --- a/src/vs/workbench/browser/media/images/git/initialze.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/next-alt1.svg b/src/vs/workbench/browser/media/images/git/next-alt1.svg deleted file mode 100644 index d2660e6e90..0000000000 --- a/src/vs/workbench/browser/media/images/git/next-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/previous-alt1.svg b/src/vs/workbench/browser/media/images/git/previous-alt1.svg deleted file mode 100644 index 6f8d0cbcb6..0000000000 --- a/src/vs/workbench/browser/media/images/git/previous-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/refresh-alt1.svg b/src/vs/workbench/browser/media/images/git/refresh-alt1.svg deleted file mode 100644 index a940b8ef4a..0000000000 --- a/src/vs/workbench/browser/media/images/git/refresh-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/stage-alt1.svg b/src/vs/workbench/browser/media/images/git/stage-alt1.svg deleted file mode 100644 index fb50c6c284..0000000000 --- a/src/vs/workbench/browser/media/images/git/stage-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/git/unstage-alt1.svg b/src/vs/workbench/browser/media/images/git/unstage-alt1.svg deleted file mode 100644 index ae942eb674..0000000000 --- a/src/vs/workbench/browser/media/images/git/unstage-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/git/whitespace-alt1.svg b/src/vs/workbench/browser/media/images/git/whitespace-alt1.svg deleted file mode 100644 index b17a38ab07..0000000000 --- a/src/vs/workbench/browser/media/images/git/whitespace-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/array-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/array-alt1.svg deleted file mode 100644 index b058a7ca9c..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/array-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/boolean-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/boolean-alt1.svg deleted file mode 100644 index 8fbcf89f2f..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/boolean-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/class-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/class-alt1.svg deleted file mode 100644 index c939df47de..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/class-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/close-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/close-alt1.svg deleted file mode 100644 index 1d8840d927..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/color-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/color-alt1.svg deleted file mode 100644 index 914bb6f48d..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/color-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/constant-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/constant-alt1.svg deleted file mode 100644 index bbb9e6dcbf..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/constant-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/enum-member-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/enum-member-alt1.svg deleted file mode 100644 index e182868e71..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/enum-member-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/enumerator-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/enumerator-alt1.svg deleted file mode 100644 index 7b87fce320..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/enumerator-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/event-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/event-alt1.svg deleted file mode 100644 index 9c7c2504c2..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/event-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/field-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/field-alt1.svg deleted file mode 100644 index e547fb51a2..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/field-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/file-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/file-alt1.svg deleted file mode 100644 index 9a0f5212ac..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/file-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/folder-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/folder-alt1.svg deleted file mode 100644 index 8d3f68206e..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/folder-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/info-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/info-alt1.svg deleted file mode 100644 index ef9fe8777a..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/info-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/interface-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/interface-alt1.svg deleted file mode 100644 index 9114ce3f3e..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/interface-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/key-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/key-alt1.svg deleted file mode 100644 index 58c6cf4ca1..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/key-alt1.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/keyword-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/keyword-alt1.svg deleted file mode 100644 index f21364efec..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/keyword-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/lightbulb-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/lightbulb-alt1.svg deleted file mode 100644 index 1583a31632..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/lightbulb-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/lightbulb-autofix-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/lightbulb-autofix-alt1.svg deleted file mode 100644 index d5ef68f9b8..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/lightbulb-autofix-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/method-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/method-alt1.svg deleted file mode 100644 index 392febfaa6..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/method-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/namespace-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/namespace-alt1.svg deleted file mode 100644 index bb4c103c75..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/namespace-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/numeric-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/numeric-alt1.svg deleted file mode 100644 index 90cf05e747..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/numeric-alt1.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/operator-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/operator-alt1.svg deleted file mode 100644 index 20f50387a6..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/operator-alt1.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/parameter-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/parameter-alt1.svg deleted file mode 100644 index 00198f67f4..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/parameter-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/property-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/property-alt1.svg deleted file mode 100644 index 828113202a..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/property-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/reference-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/reference-alt1.svg deleted file mode 100644 index aabfc34c3e..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/reference-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/ruler-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/ruler-alt1.svg deleted file mode 100644 index eec16f41fb..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/ruler-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/snippet-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/snippet-alt1.svg deleted file mode 100644 index ee82045f2a..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/snippet-alt1.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/string-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/string-alt1.svg deleted file mode 100644 index 1aa09c086c..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/string-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/structure-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/structure-alt1.svg deleted file mode 100644 index f0e857ed7c..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/structure-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/intellisense/variable-alt1.svg b/src/vs/workbench/browser/media/images/intellisense/variable-alt1.svg deleted file mode 100644 index 8cf0dbb711..0000000000 --- a/src/vs/workbench/browser/media/images/intellisense/variable-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/misc/clear-alt1.svg b/src/vs/workbench/browser/media/images/misc/clear-alt1.svg deleted file mode 100644 index 0e624a2319..0000000000 --- a/src/vs/workbench/browser/media/images/misc/clear-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/fold-alt1.svg b/src/vs/workbench/browser/media/images/misc/fold-alt1.svg deleted file mode 100644 index 69efb3e695..0000000000 --- a/src/vs/workbench/browser/media/images/misc/fold-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/misc/gotofile-alt1.svg b/src/vs/workbench/browser/media/images/misc/gotofile-alt1.svg deleted file mode 100644 index aabfc34c3e..0000000000 --- a/src/vs/workbench/browser/media/images/misc/gotofile-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/json-alt1.svg b/src/vs/workbench/browser/media/images/misc/json-alt1.svg deleted file mode 100644 index 9e8f99141f..0000000000 --- a/src/vs/workbench/browser/media/images/misc/json-alt1.svg +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/keyboard-alt1.svg b/src/vs/workbench/browser/media/images/misc/keyboard-alt1.svg deleted file mode 100644 index 6181acae7e..0000000000 --- a/src/vs/workbench/browser/media/images/misc/keyboard-alt1.svg +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/more-alt1.svg b/src/vs/workbench/browser/media/images/misc/more-alt1.svg deleted file mode 100644 index 3d7068f6b4..0000000000 --- a/src/vs/workbench/browser/media/images/misc/more-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/precedence-alt1.svg b/src/vs/workbench/browser/media/images/misc/precedence-alt1.svg deleted file mode 100644 index 2609f1f40f..0000000000 --- a/src/vs/workbench/browser/media/images/misc/precedence-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/preview-alt1.svg b/src/vs/workbench/browser/media/images/misc/preview-alt1.svg deleted file mode 100644 index 25bf0b58bb..0000000000 --- a/src/vs/workbench/browser/media/images/misc/preview-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/misc/preview-icon-alt1.svg b/src/vs/workbench/browser/media/images/misc/preview-icon-alt1.svg deleted file mode 100644 index df907d5dd1..0000000000 --- a/src/vs/workbench/browser/media/images/misc/preview-icon-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/misc/split-alt1.svg b/src/vs/workbench/browser/media/images/misc/split-alt1.svg deleted file mode 100644 index c92025ddd9..0000000000 --- a/src/vs/workbench/browser/media/images/misc/split-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/misc/unfold-alt1.svg b/src/vs/workbench/browser/media/images/misc/unfold-alt1.svg deleted file mode 100644 index bb57558f60..0000000000 --- a/src/vs/workbench/browser/media/images/misc/unfold-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/notifications/close-alt1.svg b/src/vs/workbench/browser/media/images/notifications/close-alt1.svg deleted file mode 100644 index 64618b6176..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/closeall-alt1.svg b/src/vs/workbench/browser/media/images/notifications/closeall-alt1.svg deleted file mode 100644 index 72bf0a8b54..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/closeall-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/configure-alt1.svg b/src/vs/workbench/browser/media/images/notifications/configure-alt1.svg deleted file mode 100644 index 7db1664af7..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/configure-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/down-alt1.svg b/src/vs/workbench/browser/media/images/notifications/down-alt1.svg deleted file mode 100644 index 7042b08fdd..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/down-alt1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/error-alt1.svg b/src/vs/workbench/browser/media/images/notifications/error-alt1.svg deleted file mode 100644 index e39bf5e0e4..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/error-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/notifications/info-alt1.svg b/src/vs/workbench/browser/media/images/notifications/info-alt1.svg deleted file mode 100644 index 4a597c7b80..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/info-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/up-alt1.svg b/src/vs/workbench/browser/media/images/notifications/up-alt1.svg deleted file mode 100644 index d5edcc4c30..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/up-alt1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/notifications/warning-alt1.svg b/src/vs/workbench/browser/media/images/notifications/warning-alt1.svg deleted file mode 100644 index 948c0b4dec..0000000000 --- a/src/vs/workbench/browser/media/images/notifications/warning-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/add-alt1.svg b/src/vs/workbench/browser/media/images/panel/add-alt1.svg deleted file mode 100644 index fb50c6c284..0000000000 --- a/src/vs/workbench/browser/media/images/panel/add-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/panel/clear-alt1.svg b/src/vs/workbench/browser/media/images/panel/clear-alt1.svg deleted file mode 100644 index 63be0fae21..0000000000 --- a/src/vs/workbench/browser/media/images/panel/clear-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/close-all-alt1.svg b/src/vs/workbench/browser/media/images/panel/close-all-alt1.svg deleted file mode 100644 index 8af24a5b1e..0000000000 --- a/src/vs/workbench/browser/media/images/panel/close-all-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/close-alt1.svg b/src/vs/workbench/browser/media/images/panel/close-alt1.svg deleted file mode 100644 index 3818f7d535..0000000000 --- a/src/vs/workbench/browser/media/images/panel/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/panel/collapse-all-alt1.svg b/src/vs/workbench/browser/media/images/panel/collapse-all-alt1.svg deleted file mode 100644 index f2e0e5dd5f..0000000000 --- a/src/vs/workbench/browser/media/images/panel/collapse-all-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/panel/down-alt1.svg b/src/vs/workbench/browser/media/images/panel/down-alt1.svg deleted file mode 100644 index de3313624a..0000000000 --- a/src/vs/workbench/browser/media/images/panel/down-alt1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/gear-alt1.svg b/src/vs/workbench/browser/media/images/panel/gear-alt1.svg deleted file mode 100644 index 7db1664af7..0000000000 --- a/src/vs/workbench/browser/media/images/panel/gear-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/panel/gotofile-alt1.svg b/src/vs/workbench/browser/media/images/panel/gotofile-alt1.svg deleted file mode 100644 index aabfc34c3e..0000000000 --- a/src/vs/workbench/browser/media/images/panel/gotofile-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/kill-alt1.svg b/src/vs/workbench/browser/media/images/panel/kill-alt1.svg deleted file mode 100644 index bc44829073..0000000000 --- a/src/vs/workbench/browser/media/images/panel/kill-alt1.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/panel/output-lock-alt1.svg b/src/vs/workbench/browser/media/images/panel/output-lock-alt1.svg deleted file mode 100644 index 70d268965a..0000000000 --- a/src/vs/workbench/browser/media/images/panel/output-lock-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/panel/output-unlock-alt1.svg b/src/vs/workbench/browser/media/images/panel/output-unlock-alt1.svg deleted file mode 100644 index cf8268d37d..0000000000 --- a/src/vs/workbench/browser/media/images/panel/output-unlock-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/panel/split-horizontal-alt1.svg b/src/vs/workbench/browser/media/images/panel/split-horizontal-alt1.svg deleted file mode 100644 index c92025ddd9..0000000000 --- a/src/vs/workbench/browser/media/images/panel/split-horizontal-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/panel/split-vertical-alt1.svg b/src/vs/workbench/browser/media/images/panel/split-vertical-alt1.svg deleted file mode 100644 index f407c08fa3..0000000000 --- a/src/vs/workbench/browser/media/images/panel/split-vertical-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/panel/up-alt1.svg b/src/vs/workbench/browser/media/images/panel/up-alt1.svg deleted file mode 100644 index e7ac370945..0000000000 --- a/src/vs/workbench/browser/media/images/panel/up-alt1.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/search/case-sensitive-alt1.svg b/src/vs/workbench/browser/media/images/search/case-sensitive-alt1.svg deleted file mode 100644 index 418172b686..0000000000 --- a/src/vs/workbench/browser/media/images/search/case-sensitive-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/search/clear-alt1.svg b/src/vs/workbench/browser/media/images/search/clear-alt1.svg deleted file mode 100644 index 890a6cddaa..0000000000 --- a/src/vs/workbench/browser/media/images/search/clear-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/search/collapse-all-alt1.svg b/src/vs/workbench/browser/media/images/search/collapse-all-alt1.svg deleted file mode 100644 index f2e0e5dd5f..0000000000 --- a/src/vs/workbench/browser/media/images/search/collapse-all-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/search/collapse-alt1.svg b/src/vs/workbench/browser/media/images/search/collapse-alt1.svg deleted file mode 100644 index 829e53760f..0000000000 --- a/src/vs/workbench/browser/media/images/search/collapse-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/search/exclude-alt1.svg b/src/vs/workbench/browser/media/images/search/exclude-alt1.svg deleted file mode 100644 index 2257ec6dae..0000000000 --- a/src/vs/workbench/browser/media/images/search/exclude-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/search/expand-alt1.svg b/src/vs/workbench/browser/media/images/search/expand-alt1.svg deleted file mode 100644 index a1085f2ad0..0000000000 --- a/src/vs/workbench/browser/media/images/search/expand-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/search/more-alt1.svg b/src/vs/workbench/browser/media/images/search/more-alt1.svg deleted file mode 100644 index a83faaa6ff..0000000000 --- a/src/vs/workbench/browser/media/images/search/more-alt1.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/src/vs/workbench/browser/media/images/search/refresh-alt1.svg b/src/vs/workbench/browser/media/images/search/refresh-alt1.svg deleted file mode 100644 index a940b8ef4a..0000000000 --- a/src/vs/workbench/browser/media/images/search/refresh-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/search/regex-alt1.svg b/src/vs/workbench/browser/media/images/search/regex-alt1.svg deleted file mode 100644 index bffb311a5b..0000000000 --- a/src/vs/workbench/browser/media/images/search/regex-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/search/remove-alt1.svg b/src/vs/workbench/browser/media/images/search/remove-alt1.svg deleted file mode 100644 index 64618b6176..0000000000 --- a/src/vs/workbench/browser/media/images/search/remove-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/search/replace-all-alt1.svg b/src/vs/workbench/browser/media/images/search/replace-all-alt1.svg deleted file mode 100644 index 1ef9b63cd6..0000000000 --- a/src/vs/workbench/browser/media/images/search/replace-all-alt1.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/src/vs/workbench/browser/media/images/search/replace-alt1.svg b/src/vs/workbench/browser/media/images/search/replace-alt1.svg deleted file mode 100644 index 0979845e83..0000000000 --- a/src/vs/workbench/browser/media/images/search/replace-alt1.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/src/vs/workbench/browser/media/images/search/stop-alt1.svg b/src/vs/workbench/browser/media/images/search/stop-alt1.svg deleted file mode 100644 index 52f3aa26ce..0000000000 --- a/src/vs/workbench/browser/media/images/search/stop-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/search/whole-word-alt1.svg b/src/vs/workbench/browser/media/images/search/whole-word-alt1.svg deleted file mode 100644 index 8a18eed8de..0000000000 --- a/src/vs/workbench/browser/media/images/search/whole-word-alt1.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/vs/workbench/browser/media/images/tree/close-alt1.svg b/src/vs/workbench/browser/media/images/tree/close-alt1.svg deleted file mode 100644 index 3818f7d535..0000000000 --- a/src/vs/workbench/browser/media/images/tree/close-alt1.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/src/vs/workbench/browser/media/images/tree/collapse-alt1.svg b/src/vs/workbench/browser/media/images/tree/collapse-alt1.svg deleted file mode 100644 index f6e6553774..0000000000 --- a/src/vs/workbench/browser/media/images/tree/collapse-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/tree/dirty-alt1.svg b/src/vs/workbench/browser/media/images/tree/dirty-alt1.svg deleted file mode 100644 index e391c3b085..0000000000 --- a/src/vs/workbench/browser/media/images/tree/dirty-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/media/images/tree/expand-alt1.svg b/src/vs/workbench/browser/media/images/tree/expand-alt1.svg deleted file mode 100644 index a98a85b340..0000000000 --- a/src/vs/workbench/browser/media/images/tree/expand-alt1.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index cbd07b4039..cc98b6a610 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -61,13 +61,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { //#endregion private globalActionBar: ActionBar; - private globalActivityIdToActions: Map = new Map(); + private globalActivityIdToActions: { [globalActivityId: string]: GlobalActivityAction; } = Object.create(null); private cachedViewlets: ICachedViewlet[] = []; - private compositeBar: CompositeBar; - private compositeActions: Map = new Map(); - + private compositeActions: { [compositeId: string]: { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } } = Object.create(null); private readonly viewletDisposables: Map = new Map(); constructor( @@ -171,7 +169,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { throw illegalArgument('badge'); } - const action = this.globalActivityIdToActions.get(globalActivityId); + const action = this.globalActivityIdToActions[globalActivityId]; if (!action) { throw illegalArgument('globalActivityId'); } @@ -183,15 +181,14 @@ export class ActivitybarPart extends Part implements IActivityBarService { createContentArea(parent: HTMLElement): HTMLElement { this.element = parent; - const content = document.createElement('div'); addClass(content, 'content'); parent.appendChild(content); - // Viewlets action bar + // Top Actionbar with action items for each viewlet action this.compositeBar.create(content); - // Global action bar + // Top Actionbar with action items for each viewlet action const globalActivities = document.createElement('div'); addClass(globalActivities, 'global-activity'); content.appendChild(globalActivities); @@ -211,7 +208,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { const borderColor = this.getColor(ACTIVITY_BAR_BORDER) || this.getColor(contrastBorder); const isPositionLeft = this.layoutService.getSideBarPosition() === SideBarPosition.LEFT; - container.style.boxSizing = borderColor && isPositionLeft ? 'border-box' : ''; + container.style.boxSizing = borderColor && isPositionLeft ? 'border-box' : null; container.style.borderRightWidth = borderColor && isPositionLeft ? '1px' : null; container.style.borderRightStyle = borderColor && isPositionLeft ? 'solid' : null; container.style.borderRightColor = isPositionLeft ? borderColor : null; @@ -246,13 +243,13 @@ export class ActivitybarPart extends Part implements IActivityBarService { })); actions.forEach(a => { - this.globalActivityIdToActions.set(a.id, a); + this.globalActivityIdToActions[a.id] = a; this.globalActionBar.push(a); }); } private getCompositeActions(compositeId: string): { activityAction: ViewletActivityAction, pinnedAction: ToggleCompositePinnedAction } { - let compositeActions = this.compositeActions.get(compositeId); + let compositeActions = this.compositeActions[compositeId]; if (!compositeActions) { const viewlet = this.viewletService.getViewlet(compositeId); if (viewlet) { @@ -268,7 +265,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { }; } - this.compositeActions.set(compositeId, compositeActions); + this.compositeActions[compositeId] = compositeActions; } return compositeActions; @@ -344,11 +341,11 @@ export class ActivitybarPart extends Part implements IActivityBarService { private hideComposite(compositeId: string): void { this.compositeBar.hideComposite(compositeId); - const compositeActions = this.compositeActions.get(compositeId); + const compositeActions = this.compositeActions[compositeId]; if (compositeActions) { compositeActions.activityAction.dispose(); compositeActions.pinnedAction.dispose(); - this.compositeActions.delete(compositeId); + delete this.compositeActions[compositeId]; } } diff --git a/src/vs/workbench/browser/parts/compositeBar.ts b/src/vs/workbench/browser/parts/compositeBar.ts index 223fb6f42a..7f21c71b8e 100644 --- a/src/vs/workbench/browser/parts/compositeBar.ts +++ b/src/vs/workbench/browser/parts/compositeBar.ts @@ -427,7 +427,7 @@ export class CompositeBar extends Widget implements ICompositeBar { }); } - private getContextMenuActions(): ReadonlyArray { + private getContextMenuActions(): IAction[] { const actions: IAction[] = this.model.visibleItems .map(({ id, name, activityAction }) => ({ id, diff --git a/src/vs/workbench/browser/parts/compositeBarActions.ts b/src/vs/workbench/browser/parts/compositeBarActions.ts index ba7313c62e..e77d9557f9 100644 --- a/src/vs/workbench/browser/parts/compositeBarActions.ts +++ b/src/vs/workbench/browser/parts/compositeBarActions.ts @@ -549,11 +549,11 @@ export class CompositeActionViewItem extends ActivityActionViewItem { })); // Activate on drag over to reveal targets - [this.badge, this.label].forEach(b => this._register(new DelayedDragHandler(b, () => { + [this.badge, this.label].forEach(b => new DelayedDragHandler(b, () => { if (!this.compositeTransfer.hasData(DraggedCompositeIdentifier.prototype) && !this.getAction().checked) { this.getAction().run(); } - }))); + })); this.updateStyles(); } diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 8333c74227..6bc5648cdc 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/compositepart'; import * as nls from 'vs/nls'; import { defaultGenerator } from 'vs/base/common/idGenerator'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import * as strings from 'vs/base/common/strings'; import { Emitter } from 'vs/base/common/event'; import * as errors from 'vs/base/common/errors'; @@ -18,13 +18,13 @@ import { IAction } from 'vs/base/common/actions'; import { Part, IPartOptions } from 'vs/workbench/browser/part'; import { Composite, CompositeRegistry } from 'vs/workbench/browser/composite'; import { IComposite } from 'vs/workbench/common/composite'; -import { ScopedProgressService } from 'vs/workbench/services/progress/browser/localProgressService'; +import { ScopedProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -50,7 +50,7 @@ export interface ICompositeTitleLabel { interface CompositeItem { composite: Composite; disposable: IDisposable; - localProgressService: ILocalProgressService; + progressService: IProgressService; } export abstract class CompositePart extends Part { @@ -60,8 +60,8 @@ export abstract class CompositePart extends Part { protected toolBar: ToolBar; - private mapCompositeToCompositeContainer = new Map(); - private mapActionsBindingToComposite = new Map void>(); + private mapCompositeToCompositeContainer: { [compositeId: string]: HTMLElement; }; + private mapActionsBindingToComposite: { [compositeId: string]: () => void; }; private activeComposite: Composite | null; private lastActiveCompositeId: string; private instantiatedCompositeItems: Map; @@ -91,6 +91,8 @@ export abstract class CompositePart extends Part { ) { super(id, options, themeService, storageService, layoutService); + this.mapCompositeToCompositeContainer = {}; + this.mapActionsBindingToComposite = {}; this.activeComposite = null; this.instantiatedCompositeItems = new Map(); this.lastActiveCompositeId = storageService.get(activeCompositeSettingsKey, StorageScope.WORKSPACE, this.defaultCompositeId); @@ -169,17 +171,17 @@ export abstract class CompositePart extends Part { // Instantiate composite from registry otherwise const compositeDescriptor = this.registry.getComposite(id); if (compositeDescriptor) { - const localProgressService = this.instantiationService.createInstance(ScopedProgressService, this.progressBar, compositeDescriptor.id, isActive); - const compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection([ILocalProgressService, localProgressService])); + const progressService = this.instantiationService.createInstance(ScopedProgressService, this.progressBar, compositeDescriptor.id, isActive); + const compositeInstantiationService = this.instantiationService.createChild(new ServiceCollection([IProgressService, progressService])); const composite = compositeDescriptor.instantiate(compositeInstantiationService); - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; // Remember as Instantiated - this.instantiatedCompositeItems.set(id, { composite, disposable: disposables, localProgressService }); + this.instantiatedCompositeItems.set(id, { composite, disposable: toDisposable(() => dispose(disposables)), progressService }); // Register to title area update events from the composite - disposables.add(composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId()), this)); + composite.onTitleAreaUpdate(() => this.onTitleAreaUpdate(composite.getId()), this, disposables); return composite; } @@ -204,7 +206,7 @@ export abstract class CompositePart extends Part { this.lastActiveCompositeId = this.activeComposite.getId(); // Composites created for the first time - let compositeContainer = this.mapCompositeToCompositeContainer.get(composite.getId()); + let compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()]; if (!compositeContainer) { // Build Container off-DOM @@ -216,7 +218,13 @@ export abstract class CompositePart extends Part { composite.updateStyles(); // Remember composite container - this.mapCompositeToCompositeContainer.set(composite.getId(), compositeContainer); + this.mapCompositeToCompositeContainer[composite.getId()] = compositeContainer; + } + + // Report progress for slow loading composites (but only if we did not create the composites before already) + const compositeItem = this.instantiatedCompositeItems.get(composite.getId()); + if (compositeItem && !compositeContainer) { + compositeItem.progressService.showWhile(Promise.resolve(), this.layoutService.isRestored() ? 800 : 3200 /* less ugly initial startup */); } // Fill Content and Actions @@ -242,10 +250,10 @@ export abstract class CompositePart extends Part { } // Handle Composite Actions - let actionsBinding = this.mapActionsBindingToComposite.get(composite.getId()); + let actionsBinding = this.mapActionsBindingToComposite[composite.getId()]; if (!actionsBinding) { actionsBinding = this.collectCompositeActions(composite); - this.mapActionsBindingToComposite.set(composite.getId(), actionsBinding); + this.mapActionsBindingToComposite[composite.getId()] = actionsBinding; } actionsBinding(); @@ -298,13 +306,13 @@ export abstract class CompositePart extends Part { // Actions const actionsBinding = this.collectCompositeActions(this.activeComposite); - this.mapActionsBindingToComposite.set(this.activeComposite.getId(), actionsBinding); + this.mapActionsBindingToComposite[this.activeComposite.getId()] = actionsBinding; actionsBinding(); } // Otherwise invalidate actions binding for next time when the composite becomes visible else { - this.mapActionsBindingToComposite.delete(compositeId); + delete this.mapActionsBindingToComposite[compositeId]; } } @@ -358,16 +366,14 @@ export abstract class CompositePart extends Part { const composite = this.activeComposite; this.activeComposite = null; - const compositeContainer = this.mapCompositeToCompositeContainer.get(composite.getId()); + const compositeContainer = this.mapCompositeToCompositeContainer[composite.getId()]; // Indicate to Composite composite.setVisible(false); // Take Container Off-DOM and hide - if (compositeContainer) { - compositeContainer.remove(); - hide(compositeContainer); - } + compositeContainer.remove(); + hide(compositeContainer); // Clear any running Progress this.progressBar.stop().hide(); @@ -456,17 +462,17 @@ export abstract class CompositePart extends Part { return contentContainer; } - getProgressIndicator(id: string): ILocalProgressService | null { + getProgressIndicator(id: string): IProgressService | null { const compositeItem = this.instantiatedCompositeItems.get(id); - return compositeItem ? compositeItem.localProgressService : null; + return compositeItem ? compositeItem.progressService : null; } - protected getActions(): ReadonlyArray { + protected getActions(): IAction[] { return []; } - protected getSecondaryActions(): ReadonlyArray { + protected getSecondaryActions(): IAction[] { return []; } @@ -490,8 +496,8 @@ export abstract class CompositePart extends Part { return false; // do not remove active composite } - this.mapCompositeToCompositeContainer.delete(compositeId); - this.mapActionsBindingToComposite.delete(compositeId); + delete this.mapCompositeToCompositeContainer[compositeId]; + delete this.mapActionsBindingToComposite[compositeId]; const compositeItem = this.instantiatedCompositeItems.get(compositeId); if (compositeItem) { compositeItem.composite.dispose(); @@ -503,8 +509,8 @@ export abstract class CompositePart extends Part { } dispose(): void { - this.mapCompositeToCompositeContainer.clear(); - this.mapActionsBindingToComposite.clear(); + this.mapCompositeToCompositeContainer = null!; // StrictNullOverride: nulling out ok in dispose + this.mapActionsBindingToComposite = null!; // StrictNullOverride: nulling out ok in dispose this.instantiatedCompositeItems.forEach(compositeItem => { compositeItem.composite.dispose(); diff --git a/src/vs/workbench/browser/parts/editor/baseEditor.ts b/src/vs/workbench/browser/parts/editor/baseEditor.ts index 5df7d489e9..582e82cd22 100644 --- a/src/vs/workbench/browser/parts/editor/baseEditor.ts +++ b/src/vs/workbench/browser/parts/editor/baseEditor.ts @@ -15,7 +15,6 @@ import { URI } from 'vs/base/common/uri'; import { Event } from 'vs/base/common/event'; import { isEmptyObject } from 'vs/base/common/types'; import { DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; -import { MementoObject } from 'vs/workbench/common/memento'; /** * The base class of editors in the workbench. Editors register themselves for specific editor inputs. @@ -178,7 +177,7 @@ export class EditorMemento implements IEditorMemento { constructor( private _id: string, private key: string, - private memento: MementoObject, + private memento: object, private limit: number, private editorGroupService: IEditorGroupsService ) { } diff --git a/src/vs/workbench/browser/parts/editor/binaryEditor.ts b/src/vs/workbench/browser/parts/editor/binaryEditor.ts index 6210dabe22..74b9153fd8 100644 --- a/src/vs/workbench/browser/parts/editor/binaryEditor.ts +++ b/src/vs/workbench/browser/parts/editor/binaryEditor.ts @@ -15,11 +15,11 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ResourceViewerContext, ResourceViewer } from 'vs/workbench/browser/parts/editor/resourceViewer'; import { URI } from 'vs/base/common/uri'; import { Dimension, size, clearNode } from 'vs/base/browser/dom'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { CancellationToken } from 'vs/base/common/cancellation'; import { dispose } from 'vs/base/common/lifecycle'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; export interface IOpenCallbacks { openInternal: (input: EditorInput, options: EditorOptions) => Promise; @@ -48,7 +48,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { callbacks: IOpenCallbacks, telemetryService: ITelemetryService, themeService: IThemeService, - @IFileService private readonly fileService: IFileService, + @ITextFileService private readonly textFileService: ITextFileService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IStorageService storageService: IStorageService ) { @@ -89,11 +89,7 @@ export abstract class BaseBinaryResourceEditor extends BaseEditor { } // Render Input - if (this.resourceViewerContext) { - this.resourceViewerContext.dispose(); - } - - this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, this.fileService, this.binaryContainer, this.scrollbar, { + this.resourceViewerContext = ResourceViewer.show({ name: model.getName(), resource: model.getResource(), size: model.getSize(), etag: model.getETag(), mime: model.getMime() }, this.textFileService, this.binaryContainer, this.scrollbar, { openInternalClb: () => this.handleOpenInternalCallback(input, options), openExternalClb: this.environmentService.configuration.remoteAuthority ? undefined : resource => this.callbacks.openExternal(resource), metadataClb: meta => this.handleMetadataChanged(meta) diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts index 54c3a6c30a..0bb6a8cf6c 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbs.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbs.ts @@ -122,7 +122,7 @@ Registry.as(Extensions.Configuration).registerConfigurat 'breadcrumbs.enabled': { description: localize('enabled', "Enable/disable navigation breadcrumbs."), type: 'boolean', - default: true + default: false }, // 'breadcrumbs.useQuickPick': { // description: localize('useQuickPick', "Use quick pick instead of breadcrumb-pickers."), diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 425a18d823..d7ce23e96a 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -384,14 +384,14 @@ export class BreadcrumbsControl { this._breadcrumbsPickerShowing = true; this._updateCkBreadcrumbsActive(); - return combinedDisposable( + return combinedDisposable([ picker, selectListener, focusListener, zoomListener, focusTracker, blurListener - ); + ]); }, getAnchor: () => { let maxInnerWidth = window.innerWidth - 8 /*a little less the full widget*/; @@ -494,17 +494,17 @@ MenuRegistry.appendMenuItem(MenuId.CommandPalette, { category: localize('cmd.category', "View") } }); -/* {{SQL CARBON EDIT}} - Disable unused menu item -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - order: 3, - command: { - id: 'breadcrumbs.toggle', - title: localize('miShowBreadcrumbs', "Show &&Breadcrumbs"), - toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true) - } -}); -*/ +// {{SQL CARBON EDIT}} - Disable unused menu item +// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { +// group: '5_editor', +// order: 99, +// command: { +// id: 'breadcrumbs.toggle', +// title: localize('miToggleBreadcrumbs', "Toggle &&Breadcrumbs"), +// toggled: ContextKeyExpr.equals('config.breadcrumbs.enabled', true) +// } +// }); +// {{SQL CARBON EDIT}} - End CommandsRegistry.registerCommand('breadcrumbs.toggle', accessor => { let config = accessor.get(IConfigurationService); let value = BreadcrumbsConfig.IsEnabled.bindTo(config).getValue(); diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 0ff5cd2c78..fd4961f880 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -11,7 +11,7 @@ import { IEditorQuickOpenEntry, IQuickOpenRegistry, Extensions as QuickOpenExten import { StatusbarItemDescriptor, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { IEditorRegistry, EditorDescriptor, Extensions as EditorExtensions } from 'vs/workbench/browser/editor'; -import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext, EditorPinnedContext, EditorGroupEditorsCountContext } from 'vs/workbench/common/editor'; +import { EditorInput, IEditorInputFactory, SideBySideEditorInput, IEditorInputFactoryRegistry, Extensions as EditorInputExtensions, TextCompareEditorActiveContext } from 'vs/workbench/common/editor'; import { TextResourceEditor } from 'vs/workbench/browser/parts/editor/textResourceEditor'; import { SideBySideEditor } from 'vs/workbench/browser/parts/editor/sideBySideEditor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; @@ -52,8 +52,6 @@ import { OpenWorkspaceButtonContribution } from 'vs/workbench/browser/parts/edit import { ZoomStatusbarItem } from 'vs/workbench/browser/parts/editor/resourceViewer'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { toLocalResource } from 'vs/base/common/resources'; -import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; -import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; // Register String Editor Registry.as(EditorExtensions.Editors).registerEditor( @@ -227,17 +225,11 @@ Registry.as(EditorInputExtensions.EditorInputFactor registerEditorContribution(OpenWorkspaceButtonContribution); // Register Editor Status -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(EditorStatus, LifecyclePhase.Ready); +const statusBar = Registry.as(StatusExtensions.Statusbar); +statusBar.registerStatusbarItem(new StatusbarItemDescriptor(EditorStatus, StatusbarAlignment.RIGHT, 100 /* towards the left of the right hand side */)); // Register Zoom Status -const statusBar = Registry.as(StatusExtensions.Statusbar); -statusBar.registerStatusbarItem(new StatusbarItemDescriptor( - ZoomStatusbarItem, - 'status.imageZoom', - nls.localize('status.imageZoom', "Image Zoom"), - StatusbarAlignment.RIGHT, - 101 /* to the left of editor status (100) */) -); +statusBar.registerStatusbarItem(new StatusbarItemDescriptor(ZoomStatusbarItem, StatusbarAlignment.RIGHT, 101 /* to the left of editor status (100) */)); // Register Status Actions const registry = Registry.as(ActionExtensions.WorkbenchActions); @@ -258,7 +250,7 @@ export class QuickOpenActionContributor extends ActionBarContributor { return !!entry; } - getActions(context: any): ReadonlyArray { + getActions(context: any): IAction[] { const actions: Action[] = []; const entry = this.getEntry(context); @@ -447,11 +439,11 @@ MenuRegistry.appendMenuItem(MenuId.EmptyEditorGroupContext, { command: { id: edi // Editor Title Context Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITOR_COMMAND_ID, title: nls.localize('close', "Close") }, group: '1_close', order: 10 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeOthers', "Close Others"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 20 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: nls.localize('closeRight', "Close to the Right"), precondition: EditorGroupEditorsCountContext.notEqualsTo('1') }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_OTHER_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeOthers', "Close Others") }, group: '1_close', order: 20 }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_TO_THE_RIGHT_COMMAND_ID, title: nls.localize('closeRight', "Close to the Right") }, group: '1_close', order: 30, when: ContextKeyExpr.has('config.workbench.editor.showTabs') }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_SAVED_EDITORS_COMMAND_ID, title: nls.localize('closeAllSaved', "Close Saved") }, group: '1_close', order: 40 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.CLOSE_EDITORS_IN_GROUP_COMMAND_ID, title: nls.localize('closeAll', "Close All") }, group: '1_close', order: 50 }); -MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: nls.localize('keepOpen', "Keep Open"), precondition: EditorPinnedContext.toNegated() }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); +MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.KEEP_EDITOR_COMMAND_ID, title: nls.localize('keepOpen', "Keep Open") }, group: '3_preview', order: 10, when: ContextKeyExpr.has('config.workbench.editor.enablePreview') }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_UP, title: nls.localize('splitUp', "Split Up") }, group: '5_split', order: 10 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_DOWN, title: nls.localize('splitDown', "Split Down") }, group: '5_split', order: 20 }); MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { command: { id: editorCommands.SPLIT_EDITOR_LEFT, title: nls.localize('splitLeft', "Split Left") }, group: '5_split', order: 30 }); diff --git a/src/vs/workbench/browser/parts/editor/editorControl.ts b/src/vs/workbench/browser/parts/editor/editorControl.ts index 2b3cf2b1c6..2cd9cebdea 100644 --- a/src/vs/workbench/browser/parts/editor/editorControl.ts +++ b/src/vs/workbench/browser/parts/editor/editorControl.ts @@ -11,7 +11,7 @@ import { IEditorRegistry, Extensions as EditorExtensions, IEditorDescriptor } fr import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ILocalProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress'; +import { IProgressService, LongRunningOperation } from 'vs/platform/progress/common/progress'; import { IEditorGroupView, DEFAULT_EDITOR_MIN_DIMENSIONS, DEFAULT_EDITOR_MAX_DIMENSIONS } from 'vs/workbench/browser/parts/editor/editor'; import { Event, Emitter } from 'vs/base/common/event'; import { IVisibleEditor } from 'vs/workbench/services/editor/common/editorService'; @@ -47,11 +47,11 @@ export class EditorControl extends Disposable { private groupView: IEditorGroupView, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @ILocalProgressService localProgressService: ILocalProgressService + @IProgressService progressService: IProgressService ) { super(); - this.editorOperation = this._register(new LongRunningOperation(localProgressService)); + this.editorOperation = this._register(new LongRunningOperation(progressService)); } get activeControl(): IVisibleEditor | null { diff --git a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts index 7fde637ffc..87a52a54ea 100644 --- a/src/vs/workbench/browser/parts/editor/editorDropTarget.ts +++ b/src/vs/workbench/browser/parts/editor/editorDropTarget.ts @@ -88,10 +88,10 @@ class DropOverlay extends Themable { // Overlay contrast border (if any) const activeContrastBorderColor = this.getColor(activeContrastBorder); - this.overlay.style.outlineColor = activeContrastBorderColor || ''; - this.overlay.style.outlineOffset = activeContrastBorderColor ? '-2px' : ''; - this.overlay.style.outlineStyle = activeContrastBorderColor ? 'dashed' : ''; - this.overlay.style.outlineWidth = activeContrastBorderColor ? '2px' : ''; + this.overlay.style.outlineColor = activeContrastBorderColor; + this.overlay.style.outlineOffset = activeContrastBorderColor ? '-2px' : null; + this.overlay.style.outlineStyle = activeContrastBorderColor ? 'dashed' : null; + this.overlay.style.outlineWidth = activeContrastBorderColor ? '2px' : null; } private registerListeners(): void { diff --git a/src/vs/workbench/browser/parts/editor/editorGroupView.ts b/src/vs/workbench/browser/parts/editor/editorGroupView.ts index 9f9a9f8c55..05277917f6 100644 --- a/src/vs/workbench/browser/parts/editor/editorGroupView.ts +++ b/src/vs/workbench/browser/parts/editor/editorGroupView.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/editorgroupview'; import { EditorGroup, IEditorOpenOptions, EditorCloseEvent, ISerializedEditorGroup, isSerializedEditorGroup } from 'vs/workbench/common/editor/editorGroup'; -import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor, EditorGroupEditorsCountContext } from 'vs/workbench/common/editor'; +import { EditorInput, EditorOptions, GroupIdentifier, ConfirmResult, SideBySideEditorInput, CloseDirection, IEditorCloseEvent, EditorGroupActiveEditorDirtyContext, IEditor } from 'vs/workbench/common/editor'; import { Event, Emitter, Relay } from 'vs/base/common/event'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { addClass, addClasses, Dimension, trackFocus, toggleClass, removeClass, addDisposableListener, EventType, EventHelper, findParentWithClass, clearNode, isAncestor } from 'vs/base/browser/dom'; @@ -20,8 +20,8 @@ import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BAC import { IMoveEditorOptions, ICopyEditorOptions, ICloseEditorsFilter, IGroupChangeEvent, GroupChangeKind, EditorsOrder, GroupsOrder, ICloseEditorOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { TabsTitleControl } from 'vs/workbench/browser/parts/editor/tabsTitleControl'; import { EditorControl } from 'vs/workbench/browser/parts/editor/editorControl'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; -import { LocalProgressService } from 'vs/workbench/services/progress/browser/localProgressService'; +import { IProgressService } from 'vs/platform/progress/common/progress'; +import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; import { localize } from 'vs/nls'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; @@ -184,7 +184,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const scopedContextKeyService = this._register(this.contextKeyService.createScoped(this.element)); this.scopedInstantiationService = this.instantiationService.createChild(new ServiceCollection( [IContextKeyService, scopedContextKeyService], - [ILocalProgressService, new LocalProgressService(this.progressBar)] + [IProgressService, new ProgressService(this.progressBar)] )); // Context keys @@ -220,7 +220,6 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private handleGroupContextKeys(contextKeyServcie: IContextKeyService): void { const groupActiveEditorDirtyContextKey = EditorGroupActiveEditorDirtyContext.bindTo(contextKeyServcie); - const groupEditorsCountContext = EditorGroupEditorsCountContext.bindTo(contextKeyServcie); let activeEditorListener: IDisposable; @@ -236,17 +235,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView { } }; - // Update group contexts based on group changes + // Track the active editor and update context key that reflects + // the dirty state of this editor this._register(this.onDidGroupChange(e => { - - // Track the active editor and update context key that reflects - // the dirty state of this editor if (e.kind === GroupChangeKind.EDITOR_ACTIVE) { observeActiveEditor(); } - - // Group editors count context - groupEditorsCountContext.set(this.count); })); observeActiveEditor(); @@ -291,17 +285,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { }); // Toolbar actions - const removeGroupAction = this._register(new Action( - CLOSE_EDITOR_GROUP_COMMAND_ID, - localize('closeGroupAction', "Close"), - 'close-editor-group', - true, - () => { - this.accessor.removeGroup(this); - - return Promise.resolve(true); - })); - + const removeGroupAction = this._register(new Action(CLOSE_EDITOR_GROUP_COMMAND_ID, localize('closeGroupAction', "Close"), 'close-editor-group', true, () => { this.accessor.removeGroup(this); return Promise.resolve(true); })); const keybinding = this.keybindingService.lookupKeybinding(removeGroupAction.id); containerToolbar.push(removeGroupAction, { icon: true, label: false, keybinding: keybinding ? keybinding.getLabel() : undefined }); } @@ -424,7 +408,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private async restoreEditors(from: IEditorGroupView | ISerializedEditorGroup): Promise { if (this._group.count === 0) { - return; // nothing to show + return Promise.resolve(); // nothing to show } // Determine editor options @@ -437,7 +421,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { const activeEditor = this._group.activeEditor; if (!activeEditor) { - return; + return Promise.resolve(); } options.pinned = this._group.isPinned(activeEditor); // preserve pinned state @@ -839,34 +823,30 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private async doShowEditor(editor: EditorInput, active: boolean, options?: EditorOptions): Promise { // Show in editor control if the active editor changed - let openEditorPromise: Promise; + let openEditor: IEditor | null = null; if (active) { - openEditorPromise = (async () => { - try { - const result = await this.editorControl.openEditor(editor, options); + try { + const result = await this.editorControl.openEditor(editor, options); - // Editor change event - if (result.editorChanged) { - this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_ACTIVE, editor }); - } - - return result.control; - } catch (error) { - - // Handle errors but do not bubble them up - this.doHandleOpenEditorError(error, editor, options); - - return null; // error: return NULL as result to signal this + // Editor change event + if (result.editorChanged) { + this._onDidGroupChange.fire({ kind: GroupChangeKind.EDITOR_ACTIVE, editor }); } - })(); + + openEditor = result.control; + } catch (error) { + + // Handle errors but do not bubble them up + this.doHandleOpenEditorError(error, editor, options); + } } else { - openEditorPromise = Promise.resolve(null); // inactive: return NULL as result to signal this + openEditor = null; // inactive: return NULL as result to signal this } // Show in title control after editor control because some actions depend on it this.titleAreaControl.openEditor(editor); - return openEditorPromise; + return openEditor; } private doHandleOpenEditorError(error: Error, editor: EditorInput, options?: EditorOptions): void { @@ -912,7 +892,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { // Use the first editor as active editor const { editor, options } = editors.shift()!; - let firstOpenedEditor = await this.openEditor(editor, options); + let firstEditor = await this.openEditor(editor, options); // Open the other ones inactive const startingIndex = this.getIndexOfEditor(editor) + 1; @@ -923,12 +903,12 @@ export class EditorGroupView extends Themable implements IEditorGroupView { adjustedEditorOptions.index = startingIndex + index; const openedEditor = await this.openEditor(editor, adjustedEditorOptions); - if (!firstOpenedEditor) { - firstOpenedEditor = openedEditor; // only take if the first editor opening failed + if (!firstEditor) { + firstEditor = openedEditor; // only take if the first editor opening failed } })); - return firstOpenedEditor; + return firstEditor; } //#endregion @@ -1128,7 +1108,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { private async handleDirty(editors: EditorInput[]): Promise { if (!editors.length) { - return false; // no veto + return Promise.resolve(false); // no veto } const editor = editors.shift()!; @@ -1161,7 +1141,7 @@ export class EditorGroupView extends Themable implements IEditorGroupView { this.accessor.groups.some(groupView => groupView !== this && groupView.group.contains(editor, true /* support side by side */)) || // editor is opened in other group editor instanceof SideBySideEditorInput && this.isOpened(editor.master) // side by side editor master is still opened ) { - return false; + return Promise.resolve(false); } // Switch to editor that we want to handle and confirm to save/revert diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 577687e09b..740f98ead2 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -31,7 +31,6 @@ import { IView, orthogonal, LayoutPriority } from 'vs/base/browser/ui/grid/gridv import { onUnexpectedError } from 'vs/base/common/errors'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { MementoObject } from 'vs/workbench/common/memento'; interface IEditorPartUIState { serializedGrid: ISerializedGrid; @@ -119,8 +118,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private _preferredSize: Dimension | undefined; - private readonly workspaceMemento: MementoObject; - private readonly globalMemento: MementoObject; + private workspaceMemento: object; + private globalMemento: object; private _partOptions: IEditorPartOptions; diff --git a/src/vs/workbench/browser/parts/editor/editorStatus.ts b/src/vs/workbench/browser/parts/editor/editorStatus.ts index b39490673e..32f4cced01 100644 --- a/src/vs/workbench/browser/parts/editor/editorStatus.ts +++ b/src/vs/workbench/browser/parts/editor/editorStatus.ts @@ -5,16 +5,17 @@ import 'vs/css!./media/editorstatus'; import * as nls from 'vs/nls'; -import { runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; +import { $, append, runAtThisOrScheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { format } from 'vs/base/common/strings'; import { extname, basename } from 'vs/base/common/resources'; -import { areFunctions, withNullAsUndefined, withUndefinedAsNull } from 'vs/base/common/types'; +import { areFunctions, withNullAsUndefined } from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; +import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { Action } from 'vs/base/common/actions'; import { Language } from 'vs/base/common/platform'; import { UntitledEditorInput } from 'vs/workbench/common/editor/untitledEditorInput'; import { IFileEditorInput, EncodingMode, IEncodingSupport, toResource, SideBySideEditorInput, IEditor as IBaseEditor, IEditorInput, SideBySideEditor, IModeSupport } from 'vs/workbench/common/editor'; -import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { IUntitledEditorService } from 'vs/workbench/services/untitled/common/untitledEditorService'; import { IEditorAction } from 'vs/editor/common/editorCommon'; import { EndOfLineSequence } from 'vs/editor/common/model'; @@ -24,6 +25,7 @@ import { IndentUsingSpaces, IndentUsingTabs, DetectIndentation, IndentationToSpa import { BaseBinaryResourceEditor } from 'vs/workbench/browser/parts/editor/binaryEditor'; import { BinaryResourceDiffEditor } from 'vs/workbench/browser/parts/editor/binaryDiffEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; import { IFileService, FILES_ASSOCIATIONS_CONFIG } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IModeService, ILanguageSelection } from 'vs/editor/common/services/modeService'; @@ -31,7 +33,7 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; import { TabFocus } from 'vs/editor/common/config/commonEditorConfig'; -import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { ICommandService } from 'vs/platform/commands/common/commands'; import { IExtensionGalleryService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ITextFileService, SUPPORTED_ENCODINGS } from 'vs/workbench/services/textfile/common/textfiles'; import { ICursorPositionChangedEvent } from 'vs/editor/common/controller/cursorEvents'; @@ -48,8 +50,6 @@ import { timeout } from 'vs/base/common/async'; import { INotificationHandle, INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { Event } from 'vs/base/common/event'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; // {{SQL CARBON EDIT}} import { QueryEditorService } from 'sql/workbench/services/queryEditor/browser/queryEditorService'; @@ -277,286 +277,148 @@ const nlsMultiSelectionRange = nls.localize('multiSelectionRange', "{0} selectio const nlsMultiSelection = nls.localize('multiSelection', "{0} selections"); const nlsEOLLF = nls.localize('endOfLineLineFeed', "LF"); const nlsEOLCRLF = nls.localize('endOfLineCarriageReturnLineFeed', "CRLF"); +const nlsTabFocusMode = nls.localize('tabFocusModeEnabled', "Tab Moves Focus"); +const nlsScreenReaderDetected = nls.localize('screenReaderDetected', "Screen Reader Optimized"); +const nlsScreenReaderDetectedTitle = nls.localize('screenReaderDetectedExtra', "If you are not using a Screen Reader, please change the setting `editor.accessibilitySupport` to \"off\"."); -export class EditorStatus extends Disposable implements IWorkbenchContribution { - private tabFocusModeElement: IStatusbarEntryAccessor | null = null; - private screenRedearModeElement: IStatusbarEntryAccessor | null = null; - private indentationElement: IStatusbarEntryAccessor | null = null; - private selectionElement: IStatusbarEntryAccessor | null = null; - private encodingElement: IStatusbarEntryAccessor | null = null; - private eolElement: IStatusbarEntryAccessor | null = null; - private modeElement: IStatusbarEntryAccessor | null = null; - private metadataElement: IStatusbarEntryAccessor | null = null; +class StatusBarItem { + private _showing = true; - private readonly state = new State(); - private readonly activeEditorListeners: IDisposable[] = []; - private delayedRender: IDisposable | null = null; - private toRender: StateChange | null = null; - private screenReaderNotification: INotificationHandle | null = null; - private promptedScreenReader: boolean = false; + constructor( + private readonly element: HTMLElement, + title: string, + ) { + this.setVisible(false); + this.element.title = title; + } + + set textContent(value: string) { + this.element.textContent = value; + } + + set onclick(value: () => void) { + this.element.onclick = value; + } + + setVisible(shouldShow: boolean): void { + if (shouldShow !== this._showing) { + this._showing = shouldShow; + this.element.style.display = shouldShow ? '' : 'none'; + } + } +} + +export class EditorStatus implements IStatusbarItem { + private state: State; + private element: HTMLElement; + private tabFocusModeElement: StatusBarItem; + private screenRedearModeElement: StatusBarItem; + private indentationElement: StatusBarItem; + private selectionElement: StatusBarItem; + private encodingElement: StatusBarItem; + private eolElement: StatusBarItem; + private modeElement: StatusBarItem; + private metadataElement: StatusBarItem; + private toDispose: IDisposable[]; + private activeEditorListeners: IDisposable[]; + private delayedRender: IDisposable | null; + private toRender: StateChange | null; + private screenReaderNotification: INotificationHandle | null; constructor( @IEditorService private readonly editorService: IEditorService, - @IQuickInputService private readonly quickInputService: IQuickInputService, + @IQuickOpenService private readonly quickOpenService: IQuickOpenService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @IUntitledEditorService private readonly untitledEditorService: IUntitledEditorService, @IModeService private readonly modeService: IModeService, @ITextFileService private readonly textFileService: ITextFileService, @IConfigurationService private readonly configurationService: IConfigurationService, @INotificationService private readonly notificationService: INotificationService, - @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IStatusbarService private readonly statusbarService: IStatusbarService + @IAccessibilityService private readonly accessibilityService: IAccessibilityService ) { - super(); - - this.registerCommands(); - this.registerListeners(); + this.toDispose = []; + this.activeEditorListeners = []; + this.state = new State(); } - private registerListeners(): void { - this._register(this.editorService.onDidActiveEditorChange(() => this.updateStatusBar())); - this._register(this.untitledEditorService.onDidChangeEncoding(r => this.onResourceEncodingChange(r))); - this._register(this.textFileService.models.onModelEncodingChanged(e => this.onResourceEncodingChange((e.resource)))); - this._register(TabFocus.onDidChangeTabFocus(e => this.onTabFocusModeChange())); - } + render(container: HTMLElement): IDisposable { + this.element = append(container, $('.editor-statusbar-item')); - private registerCommands(): void { - CommandsRegistry.registerCommand({ id: 'showEditorScreenReaderNotification', handler: () => this.showScreenReaderNotification() }); - CommandsRegistry.registerCommand({ id: 'changeEditorIndentation', handler: () => this.showIndentationPicker() }); - } + this.tabFocusModeElement = new StatusBarItem( + append(this.element, $('a.editor-status-tabfocusmode.status-bar-info')), + nls.localize('disableTabMode', "Disable Accessibility Mode")); + this.tabFocusModeElement.onclick = () => this.onTabFocusModeClick(); + this.tabFocusModeElement.textContent = nlsTabFocusMode; - private showScreenReaderNotification(): void { - if (!this.screenReaderNotification) { - this.screenReaderNotification = this.notificationService.prompt( - Severity.Info, - nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like folding, minimap or word wrap are disabled when using a screen reader)"), - [{ - label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"), - run: () => { - this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); - } - }, { - label: nls.localize('screenReaderDetectedExplanation.answerNo', "No"), - run: () => { - this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER); - } - }], - { sticky: true } - ); + this.screenRedearModeElement = new StatusBarItem( + append(this.element, $('a.editor-status-screenreadermode.status-bar-info')), + nlsScreenReaderDetectedTitle); + this.screenRedearModeElement.textContent = nlsScreenReaderDetected; + this.screenRedearModeElement.onclick = () => this.onScreenReaderModeClick(); - Event.once(this.screenReaderNotification.onDidClose)(() => this.screenReaderNotification = null); - } - } + this.selectionElement = new StatusBarItem( + append(this.element, $('a.editor-status-selection')), + nls.localize('gotoLine', "Go to Line")); + this.selectionElement.onclick = () => this.onSelectionClick(); - private async showIndentationPicker(): Promise { - const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget); - if (!activeTextEditorWidget) { - return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); - } + this.indentationElement = new StatusBarItem( + append(this.element, $('a.editor-status-indentation')), + nls.localize('selectIndentation', "Select Indentation")); + this.indentationElement.onclick = () => this.onIndentationClick(); - if (!isWritableCodeEditor(activeTextEditorWidget)) { - return this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]); - } + this.encodingElement = new StatusBarItem( + append(this.element, $('a.editor-status-encoding')), + nls.localize('selectEncoding', "Select Encoding")); + this.encodingElement.onclick = () => this.onEncodingClick(); - const picks: QuickPickInput[] = [ - activeTextEditorWidget.getAction(IndentUsingSpaces.ID), - activeTextEditorWidget.getAction(IndentUsingTabs.ID), - activeTextEditorWidget.getAction(DetectIndentation.ID), - activeTextEditorWidget.getAction(IndentationToSpacesAction.ID), - activeTextEditorWidget.getAction(IndentationToTabsAction.ID), - activeTextEditorWidget.getAction(TrimTrailingWhitespaceAction.ID) - ].map((a: IEditorAction) => { - return { - id: a.id, - label: a.label, - detail: Language.isDefaultVariant() ? undefined : a.alias, - run: () => { - activeTextEditorWidget.focus(); - a.run(); + this.eolElement = new StatusBarItem( + append(this.element, $('a.editor-status-eol')), + nls.localize('selectEOL', "Select End of Line Sequence")); + this.eolElement.onclick = () => this.onEOLClick(); + + this.modeElement = new StatusBarItem( + append(this.element, $('a.editor-status-mode')), + nls.localize('selectLanguageMode', "Select Language Mode")); + this.modeElement.onclick = () => this.onModeClick(); + + this.metadataElement = new StatusBarItem( + append(this.element, $('span.editor-status-metadata')), + nls.localize('fileInfo', "File Information")); + + this.delayedRender = null; + this.toRender = null; + + this.toDispose.push( + toDisposable(() => { + if (this.delayedRender) { + this.delayedRender.dispose(); + this.delayedRender = null; } - }; - }); + }), + this.editorService.onDidActiveEditorChange(() => this.updateStatusBar()), + this.untitledEditorService.onDidChangeEncoding(r => this.onResourceEncodingChange(r)), + this.textFileService.models.onModelEncodingChanged(e => this.onResourceEncodingChange(e.resource)), + TabFocus.onDidChangeTabFocus(e => this.onTabFocusModeChange()), + ); - picks.splice(3, 0, { type: 'separator', label: nls.localize('indentConvert', "convert file") }); - picks.unshift({ type: 'separator', label: nls.localize('indentView', "change view") }); - - const action = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }); - return action && action.run(); - } - - private updateTabFocusModeElement(visible: boolean): void { - if (visible) { - if (!this.tabFocusModeElement) { - this.tabFocusModeElement = this.statusbarService.addEntry({ - text: nls.localize('tabFocusModeEnabled', "Tab Moves Focus"), - tooltip: nls.localize('disableTabMode', "Disable Accessibility Mode"), - command: 'editor.action.toggleTabFocusMode' - }, 'status.editor.tabFocusMode', nls.localize('status.editor.tabFocusMode', "Accessibility Mode"), StatusbarAlignment.RIGHT, 100.7); - } - } else { - if (this.tabFocusModeElement) { - this.tabFocusModeElement.dispose(); - this.tabFocusModeElement = null; - } - } - } - - private updateScreenReaderModeElement(visible: boolean): void { - if (visible) { - if (!this.screenRedearModeElement) { - this.screenRedearModeElement = this.statusbarService.addEntry({ - text: nls.localize('screenReaderDetected', "Screen Reader Optimized"), - tooltip: nls.localize('screenReaderDetectedExtra', "If you are not using a Screen Reader, please change the setting `editor.accessibilitySupport` to \"off\"."), - command: 'showEditorScreenReaderNotification' - }, 'status.editor.screenReaderMode', nls.localize('status.editor.screenReaderMode', "Screen Reader Mode"), StatusbarAlignment.RIGHT, 100.6); - } - } else { - if (this.screenRedearModeElement) { - this.screenRedearModeElement.dispose(); - this.screenRedearModeElement = null; - } - } - } - - private updateSelectionElement(text: string | undefined): void { - if (!text) { - if (this.selectionElement) { - dispose(this.selectionElement); - this.selectionElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('gotoLine', "Go to Line"), - command: 'workbench.action.gotoLine' - }; - - this.selectionElement = this.updateElement(this.selectionElement, props, 'status.editor.selection', nls.localize('status.editor.selection', "Editor Selection"), StatusbarAlignment.RIGHT, 100.5); - } - - private updateIndentationElement(text: string | undefined): void { - if (!text) { - if (this.indentationElement) { - dispose(this.indentationElement); - this.indentationElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('selectIndentation', "Select Indentation"), - command: 'changeEditorIndentation' - }; - - this.indentationElement = this.updateElement(this.indentationElement, props, 'status.editor.indentation', nls.localize('status.editor.indentation', "Editor Indentation"), StatusbarAlignment.RIGHT, 100.4); - } - - private updateEncodingElement(text: string | undefined): void { - if (!text) { - if (this.encodingElement) { - dispose(this.encodingElement); - this.encodingElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('selectEncoding', "Select Encoding"), - command: 'workbench.action.editor.changeEncoding' - }; - - this.encodingElement = this.updateElement(this.encodingElement, props, 'status.editor.encoding', nls.localize('status.editor.encoding', "Editor Encoding"), StatusbarAlignment.RIGHT, 100.3); - } - - private updateEOLElement(text: string | undefined): void { - if (!text) { - if (this.eolElement) { - dispose(this.eolElement); - this.eolElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('selectEOL', "Select End of Line Sequence"), - command: 'workbench.action.editor.changeEOL' - }; - - this.eolElement = this.updateElement(this.eolElement, props, 'status.editor.eol', nls.localize('status.editor.eol', "Editor End of Line"), StatusbarAlignment.RIGHT, 100.2); - } - - private updateModeElement(text: string | undefined): void { - if (!text) { - if (this.modeElement) { - dispose(this.modeElement); - this.modeElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('selectLanguageMode', "Select Language Mode"), - command: 'workbench.action.editor.changeLanguageMode' - }; - - this.modeElement = this.updateElement(this.modeElement, props, 'status.editor.mode', nls.localize('status.editor.mode', "Editor Language"), StatusbarAlignment.RIGHT, 100.1); - - } - - private updateMetadataElement(text: string | undefined): void { - if (!text) { - if (this.metadataElement) { - dispose(this.metadataElement); - this.metadataElement = null; - } - - return; - } - - const props = { - text, - tooltip: nls.localize('fileInfo', "File Information") - }; - - this.metadataElement = this.updateElement(this.metadataElement, props, 'status.editor.info', nls.localize('status.editor.info', "File Information"), StatusbarAlignment.RIGHT, 100); - - } - - private updateElement(element: IStatusbarEntryAccessor | null, props: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor | null { - if (!element) { - element = this.statusbarService.addEntry(props, id, name, alignment, priority); - } else { - element.update(props); - } - - return element; + return combinedDisposable(this.toDispose); } private updateState(update: StateDelta): void { const changed = this.state.update(update); if (!changed.hasChanges()) { - return; // Nothing really changed + // Nothing really changed + return; } if (!this.toRender) { this.toRender = changed; - this.delayedRender = runAtThisOrScheduleAtNextAnimationFrame(() => { this.delayedRender = null; const toRender = this.toRender; this.toRender = null; if (toRender) { - this.doRenderNow(toRender); + this._renderNow(toRender); } }); } else { @@ -564,15 +426,68 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } } - private doRenderNow(changed: StateChange): void { - this.updateTabFocusModeElement(!!this.state.tabFocusMode); - this.updateScreenReaderModeElement(!!this.state.screenReaderMode); - this.updateIndentationElement(this.state.indentation); - this.updateSelectionElement(this.state.selectionStatus && !this.state.screenReaderMode ? this.state.selectionStatus : undefined); - this.updateEncodingElement(this.state.encoding); - this.updateEOLElement(this.state.EOL ? this.state.EOL === '\r\n' ? nlsEOLCRLF : nlsEOLLF : undefined); - this.updateModeElement(this.state.mode); - this.updateMetadataElement(this.state.metadata); + private _renderNow(changed: StateChange): void { + if (changed.tabFocusMode) { + this.tabFocusModeElement.setVisible(!!this.state.tabFocusMode); + } + + if (changed.screenReaderMode) { + this.screenRedearModeElement.setVisible(!!this.state.screenReaderMode); + } + + if (changed.indentation) { + if (this.state.indentation) { + this.indentationElement.textContent = this.state.indentation; + this.indentationElement.setVisible(true); + } else { + this.indentationElement.setVisible(false); + } + } + + if (changed.selectionStatus) { + if (this.state.selectionStatus && !this.state.screenReaderMode) { + this.selectionElement.textContent = this.state.selectionStatus; + this.selectionElement.setVisible(true); + } else { + this.selectionElement.setVisible(false); + } + } + + if (changed.encoding) { + if (this.state.encoding) { + this.encodingElement.textContent = this.state.encoding; + this.encodingElement.setVisible(true); + } else { + this.encodingElement.setVisible(false); + } + } + + if (changed.EOL) { + if (this.state.EOL) { + this.eolElement.textContent = this.state.EOL === '\r\n' ? nlsEOLCRLF : nlsEOLLF; + this.eolElement.setVisible(true); + } else { + this.eolElement.setVisible(false); + } + } + + if (changed.mode) { + if (this.state.mode) { + this.modeElement.textContent = this.state.mode; + this.modeElement.setVisible(true); + } else { + this.modeElement.setVisible(false); + } + } + + if (changed.metadata) { + if (this.state.metadata) { + this.metadataElement.textContent = this.state.metadata; + this.metadataElement.setVisible(true); + } else { + this.metadataElement.setVisible(false); + } + } } private getSelectionLabel(info: IEditorSelectionStatus): string | undefined { @@ -599,6 +514,66 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return undefined; } + private onModeClick(): void { + const action = this.instantiationService.createInstance(ChangeModeAction, ChangeModeAction.ID, ChangeModeAction.LABEL); + + action.run(); + action.dispose(); + } + + private onIndentationClick(): void { + const action = this.instantiationService.createInstance(ChangeIndentationAction, ChangeIndentationAction.ID, ChangeIndentationAction.LABEL); + action.run(); + action.dispose(); + } + + private onScreenReaderModeClick(): void { + if (!this.screenReaderNotification) { + this.screenReaderNotification = this.notificationService.prompt( + Severity.Info, + nls.localize('screenReaderDetectedExplanation.question', "Are you using a screen reader to operate Azure Data Studio? (Certain features like folding, minimap or word wrap are disabled when using a screen reader)"), + [{ + label: nls.localize('screenReaderDetectedExplanation.answerYes', "Yes"), + run: () => { + this.configurationService.updateValue('editor.accessibilitySupport', 'on', ConfigurationTarget.USER); + } + }, { + label: nls.localize('screenReaderDetectedExplanation.answerNo', "No"), + run: () => { + this.configurationService.updateValue('editor.accessibilitySupport', 'off', ConfigurationTarget.USER); + } + }], + { sticky: true } + ); + + Event.once(this.screenReaderNotification.onDidClose)(() => { + this.screenReaderNotification = null; + }); + } + } + + private onSelectionClick(): void { + this.quickOpenService.show(':'); // "Go to line" + } + + private onEOLClick(): void { + const action = this.instantiationService.createInstance(ChangeEOLAction, ChangeEOLAction.ID, ChangeEOLAction.LABEL); + + action.run(); + action.dispose(); + } + + private onEncodingClick(): void { + const action = this.instantiationService.createInstance(ChangeEncodingAction, ChangeEncodingAction.ID, ChangeEncodingAction.LABEL); + + action.run(); + action.dispose(); + } + + private onTabFocusModeClick(): void { + TabFocus.setTabFocusMode(false); + } + private updateStatusBar(): void { const activeControl = this.editorService.activeControl; const activeCodeEditor = activeControl ? withNullAsUndefined(getCodeEditor(activeControl.getControl())) : undefined; @@ -692,6 +667,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (editorWidget) { const textModel = editorWidget.getModel(); if (textModel) { + // Compute mode const modeId = textModel.getLanguageIdentifier().language; info = { mode: this.modeService.getLanguageName(modeId) || undefined }; } @@ -728,6 +704,8 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { this.updateState(update); } + private promptedScreenReader: boolean = false; + private onScreenReaderModeChange(editorWidget: ICodeEditor | undefined): void { let screenReaderMode = false; @@ -737,9 +715,12 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { if (screenReaderDetected) { const screenReaderConfiguration = this.configurationService.getValue('editor').accessibilitySupport; if (screenReaderConfiguration === 'auto') { + // show explanation if (!this.promptedScreenReader) { this.promptedScreenReader = true; - setTimeout(() => this.showScreenReaderNotification(), 100); + setTimeout(() => { + this.onScreenReaderModeClick(); + }, 100); } } } @@ -755,7 +736,7 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { } private onSelectionChange(editorWidget: ICodeEditor | undefined): void { - const info: IEditorSelectionStatus = Object.create(null); + const info: IEditorSelectionStatus = {}; // We only support text based editors if (editorWidget) { @@ -849,15 +830,6 @@ export class EditorStatus extends Disposable implements IWorkbenchContribution { return !!activeControl && activeControl === control; } - - dispose(): void { - super.dispose(); - - if (this.delayedRender) { - this.delayedRender.dispose(); - this.delayedRender = null; - } - } } function isWritableCodeEditor(codeEditor: ICodeEditor | undefined): boolean { @@ -927,7 +899,7 @@ export class ChangeModeAction extends Action { // Compute mode let currentModeId: string | undefined; - let modeId: string | undefined; + let modeId: string; if (textModel) { modeId = textModel.getLanguageIdentifier().language; currentModeId = this.modeService.getLanguageName(modeId) || undefined; @@ -967,9 +939,9 @@ export class ChangeModeAction extends Action { } // Offer action to configure via settings - let configureModeAssociations: IQuickPickItem | undefined; - let configureModeSettings: IQuickPickItem | undefined; - let galleryAction: Action | undefined; + let configureModeAssociations: IQuickPickItem; + let configureModeSettings: IQuickPickItem; + let galleryAction: Action; if (hasLanguageSupport && resource) { const ext = extname(resource) || basename(resource); @@ -993,60 +965,61 @@ export class ChangeModeAction extends Action { picks.unshift(autoDetectMode); } - const pick = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language Mode"), matchOnDescription: true }); - if (!pick) { - return; - } - - if (pick === galleryAction) { - galleryAction.run(); - return; - } - - // User decided to permanently configure associations, return right after - if (pick === configureModeAssociations) { - if (resource) { - this.configureFileAssociation(resource); + return this.quickInputService.pick(picks, { placeHolder: nls.localize('pickLanguage', "Select Language Mode"), matchOnDescription: true }).then(pick => { + if (!pick) { + return; } - return; - } - // User decided to configure settings for current language - if (pick === configureModeSettings) { - this.preferencesService.configureSettingsForLanguage(withUndefinedAsNull(modeId)); - return; - } + if (pick === galleryAction) { + galleryAction.run(); + return; + } - // Change mode for active editor - const activeEditor = this.editorService.activeControl; // {{SQL CARBON EDIT}} @anthonydresser change to activeControl from active editor - if (activeEditor) { - const modeSupport = toEditorWithModeSupport(activeEditor.input); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly - if (modeSupport) { + // User decided to permanently configure associations, return right after + if (pick === configureModeAssociations) { + if (resource) { + this.configureFileAssociation(resource); + } + return; + } - // Find mode - let languageSelection: ILanguageSelection | undefined; - if (pick === autoDetectMode) { - if (textModel) { - const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER }); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly - if (resource) { - languageSelection = this.modeService.createByFilepathOrFirstLine(resource.fsPath, textModel.getLineContent(1)); + // User decided to configure settings for current language + if (pick === configureModeSettings) { + this.preferencesService.configureSettingsForLanguage(modeId); + return; + } + + // Change mode for active editor + const activeEditor = this.editorService.activeControl; // {{SQL CARBON EDIT}} @anthonydresser change to activeControl from active editor + if (activeEditor) { + const modeSupport = toEditorWithModeSupport(activeEditor.input); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly + if (modeSupport) { + + // Find mode + let languageSelection: ILanguageSelection | undefined; + if (pick === autoDetectMode) { + if (textModel) { + const resource = toResource(activeEditor.input, { supportSideBySide: SideBySideEditor.MASTER }); // {{SQL CARBON EDIT}} @anthonydresser reference input rather than activeeditor directly + if (resource) { + languageSelection = this.modeService.createByFilepathOrFirstLine(resource.fsPath, textModel.getLineContent(1)); + } } + } else { + languageSelection = this.modeService.createByLanguageName(pick.label); } - } else { - languageSelection = this.modeService.createByLanguageName(pick.label); - } - // {{SQL CARBON EDIT}} @anthonydresser preform a check before we actuall set the mode - // Change mode - if (typeof languageSelection !== 'undefined') { - QueryEditorService.sqlLanguageModeCheck(textModel, languageSelection, activeEditor).then(newTextModel => { - if (newTextModel) { - modeSupport.setMode(languageSelection.languageIdentifier.language); - } - }); + // {{SQL CARBON EDIT}} @anthonydresser preform a check before we actuall set the mode + // Change mode + if (typeof languageSelection !== 'undefined') { + QueryEditorService.sqlLanguageModeCheck(textModel, languageSelection, activeEditor).then(newTextModel => { + if (newTextModel) { + modeSupport.setMode(languageSelection.languageIdentifier.language); + } + }); + } } } - } + }); } private configureFileAssociation(resource: URI): void { @@ -1097,6 +1070,57 @@ export interface IChangeEOLEntry extends IQuickPickItem { eol: EndOfLineSequence; } +class ChangeIndentationAction extends Action { + + static readonly ID = 'workbench.action.editor.changeIndentation'; + static readonly LABEL = nls.localize('changeIndentation', "Change Indentation"); + + constructor( + actionId: string, + actionLabel: string, + @IEditorService private readonly editorService: IEditorService, + @IQuickInputService private readonly quickInputService: IQuickInputService + ) { + super(actionId, actionLabel); + } + + async run(): Promise { + const activeTextEditorWidget = getCodeEditor(this.editorService.activeTextEditorWidget); + if (!activeTextEditorWidget) { + return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); + } + + if (!isWritableCodeEditor(activeTextEditorWidget)) { + return this.quickInputService.pick([{ label: nls.localize('noWritableCodeEditor', "The active code editor is read-only.") }]); + } + + const picks: QuickPickInput[] = [ + activeTextEditorWidget.getAction(IndentUsingSpaces.ID), + activeTextEditorWidget.getAction(IndentUsingTabs.ID), + activeTextEditorWidget.getAction(DetectIndentation.ID), + activeTextEditorWidget.getAction(IndentationToSpacesAction.ID), + activeTextEditorWidget.getAction(IndentationToTabsAction.ID), + activeTextEditorWidget.getAction(TrimTrailingWhitespaceAction.ID) + ].map((a: IEditorAction) => { + return { + id: a.id, + label: a.label, + detail: Language.isDefaultVariant() ? undefined : a.alias, + run: () => { + activeTextEditorWidget.focus(); + a.run(); + } + }; + }); + + picks.splice(3, 0, { type: 'separator', label: nls.localize('indentConvert', "convert file") }); + picks.unshift({ type: 'separator', label: nls.localize('indentView', "change view") }); + + const action = await this.quickInputService.pick(picks, { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }); + return action && action.run(); + } +} + export class ChangeEOLAction extends Action { static readonly ID = 'workbench.action.editor.changeEOL'; @@ -1158,7 +1182,7 @@ export class ChangeEncodingAction extends Action { super(actionId, actionLabel); } - async run(): Promise { + run(): Promise { if (!getCodeEditor(this.editorService.activeTextEditorWidget)) { return this.quickInputService.pick([{ label: nls.localize('noEditor', "No text editor active at this time") }]); } @@ -1183,88 +1207,93 @@ export class ChangeEncodingAction extends Action { reopenWithEncodingPick = { label: nls.localize('reopenWithEncoding', "Reopen with Encoding"), detail: 'Reopen with Encoding' }; } - let action: IQuickPickItem; + let pickActionPromise: Promise; if (encodingSupport instanceof UntitledEditorInput) { - action = saveWithEncodingPick; + pickActionPromise = Promise.resolve(saveWithEncodingPick); } else if (!isWritableBaseEditor(activeControl)) { - action = reopenWithEncodingPick; + pickActionPromise = Promise.resolve(reopenWithEncodingPick); } else { - action = await this.quickInputService.pick([reopenWithEncodingPick, saveWithEncodingPick], { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }); + pickActionPromise = this.quickInputService.pick([reopenWithEncodingPick, saveWithEncodingPick], { placeHolder: nls.localize('pickAction', "Select Action"), matchOnDetail: true }); } - if (!action) { - return; - } + return pickActionPromise.then(action => { + if (!action) { + return undefined; + } - await timeout(50); // quick open is sensitive to being opened so soon after another + const resource = toResource(activeControl!.input, { supportSideBySide: SideBySideEditor.MASTER }); - const resource = toResource(activeControl!.input, { supportSideBySide: SideBySideEditor.MASTER }); - if (!resource || !this.fileService.canHandleResource(resource)) { - return null; // encoding detection only possible for resources the file service can handle - } + return timeout(50 /* quick open is sensitive to being opened so soon after another */) + .then(() => { + if (!resource || !this.fileService.canHandleResource(resource)) { + return Promise.resolve(null); // encoding detection only possible for resources the file service can handle + } - const content = await this.textFileService.read(resource, { autoGuessEncoding: true, acceptTextOnly: true }); - const guessedEncoding = content.encoding; + return this.textFileService.read(resource, { autoGuessEncoding: true, acceptTextOnly: true }).then(content => content.encoding, err => null); + }) + .then((guessedEncoding: string) => { + const isReopenWithEncoding = (action === reopenWithEncodingPick); - const isReopenWithEncoding = (action === reopenWithEncodingPick); + const configuredEncoding = this.textResourceConfigurationService.getValue(withNullAsUndefined(resource), 'files.encoding'); - const configuredEncoding = this.textResourceConfigurationService.getValue(withNullAsUndefined(resource), 'files.encoding'); + let directMatchIndex: number | undefined; + let aliasMatchIndex: number | undefined; - let directMatchIndex: number | undefined; - let aliasMatchIndex: number | undefined; + // All encodings are valid picks + const picks: QuickPickInput[] = Object.keys(SUPPORTED_ENCODINGS) + .sort((k1, k2) => { + if (k1 === configuredEncoding) { + return -1; + } else if (k2 === configuredEncoding) { + return 1; + } - // All encodings are valid picks - const picks: QuickPickInput[] = Object.keys(SUPPORTED_ENCODINGS) - .sort((k1, k2) => { - if (k1 === configuredEncoding) { - return -1; - } else if (k2 === configuredEncoding) { - return 1; - } + return SUPPORTED_ENCODINGS[k1].order - SUPPORTED_ENCODINGS[k2].order; + }) + .filter(k => { + if (k === guessedEncoding && guessedEncoding !== configuredEncoding) { + return false; // do not show encoding if it is the guessed encoding that does not match the configured + } - return SUPPORTED_ENCODINGS[k1].order - SUPPORTED_ENCODINGS[k2].order; - }) - .filter(k => { - if (k === guessedEncoding && guessedEncoding !== configuredEncoding) { - return false; // do not show encoding if it is the guessed encoding that does not match the configured - } + return !isReopenWithEncoding || !SUPPORTED_ENCODINGS[k].encodeOnly; // hide those that can only be used for encoding if we are about to decode + }) + .map((key, index) => { + if (key === encodingSupport.getEncoding()) { + directMatchIndex = index; + } else if (SUPPORTED_ENCODINGS[key].alias === encodingSupport.getEncoding()) { + aliasMatchIndex = index; + } - return !isReopenWithEncoding || !SUPPORTED_ENCODINGS[k].encodeOnly; // hide those that can only be used for encoding if we are about to decode - }) - .map((key, index) => { - if (key === encodingSupport.getEncoding()) { - directMatchIndex = index; - } else if (SUPPORTED_ENCODINGS[key].alias === encodingSupport.getEncoding()) { - aliasMatchIndex = index; - } + return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong, description: key }; + }); - return { id: key, label: SUPPORTED_ENCODINGS[key].labelLong, description: key }; - }); + const items = picks.slice() as IQuickPickItem[]; - const items = picks.slice() as IQuickPickItem[]; + // If we have a guessed encoding, show it first unless it matches the configured encoding + if (guessedEncoding && configuredEncoding !== guessedEncoding && SUPPORTED_ENCODINGS[guessedEncoding]) { + picks.unshift({ type: 'separator' }); + picks.unshift({ id: guessedEncoding, label: SUPPORTED_ENCODINGS[guessedEncoding].labelLong, description: nls.localize('guessedEncoding', "Guessed from content") }); + } - // If we have a guessed encoding, show it first unless it matches the configured encoding - if (guessedEncoding && configuredEncoding !== guessedEncoding && SUPPORTED_ENCODINGS[guessedEncoding]) { - picks.unshift({ type: 'separator' }); - picks.unshift({ id: guessedEncoding, label: SUPPORTED_ENCODINGS[guessedEncoding].labelLong, description: nls.localize('guessedEncoding', "Guessed from content") }); - } + return this.quickInputService.pick(picks, { + placeHolder: isReopenWithEncoding ? nls.localize('pickEncodingForReopen', "Select File Encoding to Reopen File") : nls.localize('pickEncodingForSave', "Select File Encoding to Save with"), + activeItem: items[typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : -1] + }).then(encoding => { + if (!encoding) { + return; + } - const encoding = await this.quickInputService.pick(picks, { - placeHolder: isReopenWithEncoding ? nls.localize('pickEncodingForReopen', "Select File Encoding to Reopen File") : nls.localize('pickEncodingForSave', "Select File Encoding to Save with"), - activeItem: items[typeof directMatchIndex === 'number' ? directMatchIndex : typeof aliasMatchIndex === 'number' ? aliasMatchIndex : -1] + const activeControl = this.editorService.activeControl; + if (!activeControl) { + return; + } + + const encodingSupport = toEditorWithEncodingSupport(activeControl.input); + if (typeof encoding.id !== 'undefined' && encodingSupport && encodingSupport.getEncoding() !== encoding.id) { + encodingSupport.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode); // Set new encoding + } + }); + }); }); - - if (!encoding) { - return; - } - - if (!this.editorService.activeControl) { - return; - } - - const activeEncodingSupport = toEditorWithEncodingSupport(this.editorService.activeControl.input); - if (typeof encoding.id !== 'undefined' && activeEncodingSupport && activeEncodingSupport.getEncoding() !== encoding.id) { - activeEncodingSupport.setEncoding(encoding.id, isReopenWithEncoding ? EncodingMode.Decode : EncodingMode.Encode); // Set new encoding - } } } diff --git a/src/vs/workbench/browser/parts/editor/media/editorstatus.css b/src/vs/workbench/browser/parts/editor/media/editorstatus.css index e19f7e75d8..1f9538dcb3 100644 --- a/src/vs/workbench/browser/parts/editor/media/editorstatus.css +++ b/src/vs/workbench/browser/parts/editor/media/editorstatus.css @@ -3,6 +3,25 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.monaco-workbench .editor-statusbar-item > a:not(:first-child) { + margin-left: 5px; +} + +.monaco-workbench .editor-statusbar-item > .editor-status-mode, +.monaco-workbench .editor-statusbar-item > .editor-status-encoding, +.monaco-workbench .editor-statusbar-item > .editor-status-eol, +.monaco-workbench .editor-statusbar-item > .editor-status-selection, +.monaco-workbench .editor-statusbar-item > .editor-status-indentation, +.monaco-workbench .editor-statusbar-item > .editor-status-metadata, +.monaco-workbench .editor-statusbar-item > .editor-status-tabfocusmode, +.monaco-workbench .editor-statusbar-item > .editor-status-screenreadermode { + padding: 0 5px 0 5px; +} + +.monaco-workbench .editor-statusbar-item > .editor-status-metadata { + cursor: default !important; +} + .monaco-workbench .screen-reader-detected-explanation { width: 420px; top: 30px; diff --git a/src/vs/workbench/browser/parts/editor/media/resourceviewer.css b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css index 5c68448e81..54be06f243 100644 --- a/src/vs/workbench/browser/parts/editor/media/resourceviewer.css +++ b/src/vs/workbench/browser/parts/editor/media/resourceviewer.css @@ -14,23 +14,19 @@ .monaco-resource-viewer.image { padding: 0; + background-position: 0 0, 8px 8px; + background-size: 16px 16px; display: flex; box-sizing: border-box; } -.monaco-resource-viewer.image img { - padding: 0; - background-position: 0 0, 8px 8px; - background-size: 16px 16px; -} - -.vs .monaco-resource-viewer.image img { +.vs .monaco-resource-viewer.image { background-image: linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)), linear-gradient(45deg, rgb(230, 230, 230) 25%, transparent 25%, transparent 75%, rgb(230, 230, 230) 75%, rgb(230, 230, 230)); } -.vs-dark .monaco-resource-viewer.image img { +.vs-dark .monaco-resource-viewer.image { background-image: linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)), linear-gradient(45deg, rgb(20, 20, 20) 25%, transparent 25%, transparent 75%, rgb(20, 20, 20) 75%, rgb(20, 20, 20)); @@ -58,10 +54,6 @@ cursor: zoom-out; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item > a.zoom-statusbar-item { - padding: 0 5px 0 5px; -} - .monaco-resource-viewer .embedded-link, .monaco-resource-viewer .embedded-link:hover { cursor: pointer; diff --git a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts index 96313c9321..2d81485130 100644 --- a/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/noTabsTitleControl.ts @@ -47,7 +47,7 @@ export class NoTabsTitleControl extends TitleControl { // Breadcrumbs this.createBreadcrumbsControl(labelContainer, { showFileIcons: false, showSymbolIcons: true, showDecorationColors: false, breadcrumbsBackground: () => Color.transparent }); toggleClass(this.titleContainer, 'breadcrumbs', Boolean(this.breadcrumbsControl)); - this._register({ dispose: () => removeClass(this.titleContainer, 'breadcrumbs') }); // import to remove because the container is a shared dom node + this.toDispose.push({ dispose: () => removeClass(this.titleContainer, 'breadcrumbs') }); // import to remove because the container is a shared dom node // Right Actions Container const actionsContainer = document.createElement('div'); diff --git a/src/vs/workbench/browser/parts/editor/resourceViewer.ts b/src/vs/workbench/browser/parts/editor/resourceViewer.ts index c37f95c3cc..ec9bb061ff 100644 --- a/src/vs/workbench/browser/parts/editor/resourceViewer.ts +++ b/src/vs/workbench/browser/parts/editor/resourceViewer.ts @@ -15,13 +15,13 @@ import { clamp } from 'vs/base/common/numbers'; import { Themable } from 'vs/workbench/common/theme'; import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { IDisposable, Disposable, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Action } from 'vs/base/common/actions'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { memoize } from 'vs/base/common/decorators'; import * as platform from 'vs/base/common/platform'; -import { IFileService } from 'vs/platform/files/common/files'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; export interface IResourceDescriptor { readonly resource: URI; @@ -78,7 +78,7 @@ export class ResourceViewer { static show( descriptor: IResourceDescriptor, - fileService: IFileService, + textFileService: ITextFileService, container: HTMLElement, scrollbar: DomScrollableElement, delegate: ResourceViewerDelegate @@ -89,7 +89,7 @@ export class ResourceViewer { // Images if (ResourceViewer.isImageResource(descriptor)) { - return ImageView.create(container, descriptor, fileService, scrollbar, delegate); + return ImageView.create(container, descriptor, textFileService, scrollbar, delegate); } // Large Files @@ -118,12 +118,12 @@ class ImageView { static create( container: HTMLElement, descriptor: IResourceDescriptor, - fileService: IFileService, + textFileService: ITextFileService, scrollbar: DomScrollableElement, delegate: ResourceViewerDelegate ): ResourceViewerContext { if (ImageView.shouldShowImageInline(descriptor)) { - return InlineImageView.create(container, descriptor, fileService, scrollbar, delegate); + return InlineImageView.create(container, descriptor, textFileService, scrollbar, delegate); } return LargeImageView.create(container, descriptor, delegate); @@ -160,7 +160,7 @@ class LargeImageView { DOM.clearNode(container); - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const label = document.createElement('p'); label.textContent = nls.localize('largeImageError', "The image is not displayed in the editor because it is too large ({0}).", size); @@ -172,10 +172,10 @@ class LargeImageView { link.setAttribute('role', 'button'); link.textContent = nls.localize('resourceOpenExternalButton', "Open image using external program?"); - disposables.add(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternal(descriptor.resource))); + disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => openExternal(descriptor.resource))); } - return disposables; + return combinedDisposable(disposables); } } @@ -212,7 +212,7 @@ class FileSeemsBinaryFileView { DOM.clearNode(container); - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const label = document.createElement('p'); label.textContent = nls.localize('nativeBinaryError', "The file is not displayed in the editor because it is either binary or uses an unsupported text encoding."); @@ -223,12 +223,12 @@ class FileSeemsBinaryFileView { link.setAttribute('role', 'button'); link.textContent = nls.localize('openAsText', "Do you want to open it anyway?"); - disposables.add(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => delegate.openInternalClb(descriptor.resource))); + disposables.push(DOM.addDisposableListener(link, DOM.EventType.CLICK, () => delegate.openInternalClb(descriptor.resource))); } scrollbar.scanDomNode(); - return disposables; + return combinedDisposable(disposables); } } @@ -359,15 +359,15 @@ class InlineImageView { static create( container: HTMLElement, descriptor: IResourceDescriptor, - fileService: IFileService, + textFileService: ITextFileService, scrollbar: DomScrollableElement, delegate: ResourceViewerDelegate ) { - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const context: ResourceViewerContext = { layout(dimension: DOM.Dimension) { }, - dispose: () => disposables.dispose() + dispose: () => combinedDisposable(disposables).dispose() }; const cacheKey = `${descriptor.resource.toString()}:${descriptor.etag}`; @@ -436,7 +436,7 @@ class InlineImageView { updateScale(scale); } - disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { + disposables.push(DOM.addDisposableListener(window, DOM.EventType.KEY_DOWN, (e: KeyboardEvent) => { if (!image) { return; } @@ -449,7 +449,7 @@ class InlineImageView { } })); - disposables.add(DOM.addDisposableListener(window, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { + disposables.push(DOM.addDisposableListener(window, DOM.EventType.KEY_UP, (e: KeyboardEvent) => { if (!image) { return; } @@ -463,7 +463,7 @@ class InlineImageView { } })); - disposables.add(DOM.addDisposableListener(container, DOM.EventType.CLICK, (e: MouseEvent) => { + disposables.push(DOM.addDisposableListener(container, DOM.EventType.CLICK, (e: MouseEvent) => { if (!image) { return; } @@ -496,7 +496,7 @@ class InlineImageView { } })); - disposables.add(DOM.addDisposableListener(container, DOM.EventType.WHEEL, (e: WheelEvent) => { + disposables.push(DOM.addDisposableListener(container, DOM.EventType.WHEEL, (e: WheelEvent) => { if (!image) { return; } @@ -518,7 +518,7 @@ class InlineImageView { updateScale(scale as number * (1 - delta * InlineImageView.SCALE_PINCH_FACTOR)); })); - disposables.add(DOM.addDisposableListener(container, DOM.EventType.SCROLL, () => { + disposables.push(DOM.addDisposableListener(container, DOM.EventType.SCROLL, () => { if (!image || !image.parentElement || scale === 'fit') { return; } @@ -536,7 +536,7 @@ class InlineImageView { image = DOM.append(container, DOM.$('img.scale-to-fit')); image.style.visibility = 'hidden'; - disposables.add(DOM.addDisposableListener(image, DOM.EventType.LOAD, e => { + disposables.push(DOM.addDisposableListener(image, DOM.EventType.LOAD, e => { if (!image) { return; } @@ -557,29 +557,25 @@ class InlineImageView { } })); - InlineImageView.imageSrc(descriptor, fileService).then(src => { - const img = container.querySelector('img'); - if (img) { - if (typeof src === 'string') { - img.src = src; - } else { - const url = URL.createObjectURL(src); - disposables.add(toDisposable(() => URL.revokeObjectURL(url))); - img.src = url; - } + InlineImageView.imageSrc(descriptor, textFileService).then(dataUri => { + const imgs = container.getElementsByTagName('img'); + if (imgs.length) { + imgs[0].src = dataUri; } }); return context; } - private static async imageSrc(descriptor: IResourceDescriptor, fileService: IFileService): Promise { + private static async imageSrc(descriptor: IResourceDescriptor, textFileService: ITextFileService): Promise { if (descriptor.resource.scheme === Schemas.data) { - return descriptor.resource.toString(true /* skip encoding */); + return Promise.resolve(descriptor.resource.toString(true /* skip encoding */)); } - const { value } = await fileService.readFile(descriptor.resource); - return new Blob([value.buffer], { type: getMime(descriptor) }); + const data = await textFileService.read(descriptor.resource, { encoding: 'base64' }); + const mime = getMime(descriptor); + + return `data:${mime};base64,${data.value}`; } } diff --git a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts index 4cbb73c524..f4411f624c 100644 --- a/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts +++ b/src/vs/workbench/browser/parts/editor/sideBySideEditor.ts @@ -169,7 +169,7 @@ export class SideBySideEditor extends BaseEditor { } if (!this.detailsEditor || !this.masterEditor) { - return; + return Promise.resolve(); } await Promise.all([ @@ -213,6 +213,8 @@ export class SideBySideEditor extends BaseEditor { this.detailsEditor.setInput(detailsInput, null, token), this.masterEditor.setInput(masterInput, options, token)] ); + + return this.focus(); } updateStyles(): void { diff --git a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts index be4e9ab2fe..933fdfe712 100644 --- a/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts +++ b/src/vs/workbench/browser/parts/editor/tabsTitleControl.ts @@ -20,12 +20,13 @@ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IMenuService } from 'vs/platform/actions/common/actions'; import { TitleControl } from 'vs/workbench/browser/parts/editor/titleControl'; import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; -import { IDisposable, dispose, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; import { ScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import { getOrSet } from 'vs/base/common/map'; -import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; // {{SQL CARBON EDIT}} -- Display the editor's tab color -import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BACKGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER, TAB_HOVER_BACKGROUND, TAB_HOVER_BORDER, TAB_UNFOCUSED_HOVER_BACKGROUND, TAB_UNFOCUSED_HOVER_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, WORKBENCH_BACKGROUND, TAB_ACTIVE_BORDER_TOP, TAB_UNFOCUSED_ACTIVE_BORDER_TOP, TAB_ACTIVE_MODIFIED_BORDER, TAB_INACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_ACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_INACTIVE_MODIFIED_BORDER } from 'vs/workbench/common/theme'; +// {{SQL CARBON EDIT}} -- Display the editor's tab color +import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; +import { TAB_INACTIVE_BACKGROUND, TAB_ACTIVE_BACKGROUND, TAB_ACTIVE_FOREGROUND, TAB_INACTIVE_FOREGROUND, TAB_BORDER, EDITOR_DRAG_AND_DROP_BACKGROUND, TAB_UNFOCUSED_ACTIVE_FOREGROUND, TAB_UNFOCUSED_INACTIVE_FOREGROUND, TAB_UNFOCUSED_ACTIVE_BORDER, TAB_ACTIVE_BORDER, TAB_HOVER_BACKGROUND, TAB_HOVER_BORDER, TAB_UNFOCUSED_HOVER_BACKGROUND, TAB_UNFOCUSED_HOVER_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, WORKBENCH_BACKGROUND, TAB_ACTIVE_BORDER_TOP, TAB_UNFOCUSED_ACTIVE_BORDER_TOP, TAB_ACTIVE_MODIFIED_BORDER, TAB_INACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_ACTIVE_MODIFIED_BORDER, TAB_UNFOCUSED_INACTIVE_MODIFIED_BORDER } from 'vs/workbench/common/theme'; import { activeContrastBorder, contrastBorder, editorBackground, breadcrumbsBackground } from 'vs/platform/theme/common/colorRegistry'; import { ResourcesDropHandler, fillResourceDataTransfers, DraggedEditorIdentifier, DraggedEditorGroupIdentifier, DragAndDropObserver } from 'vs/workbench/browser/dnd'; import { Color } from 'vs/base/common/color'; @@ -117,7 +118,7 @@ export class TabsTitleControl extends TitleControl { this.registerTabsContainerListeners(); // Tabs Scrollbar - this.tabsScrollbar = this._register(this.createTabsScrollbar(this.tabsContainer)); + this.tabsScrollbar = this.createTabsScrollbar(this.tabsContainer); tabsAndActionsContainer.appendChild(this.tabsScrollbar.getDomNode()); // Editor Toolbar Container @@ -464,13 +465,13 @@ export class TabsTitleControl extends TitleControl { // Eventing const eventsDisposable = this.registerTabListeners(tabContainer, index); - this.tabDisposeables.push(combinedDisposable(eventsDisposable, tabActionBar, tabActionRunner, editorLabel)); + this.tabDisposeables.push(combinedDisposable([eventsDisposable, tabActionBar, tabActionRunner, editorLabel])); return tabContainer; } private registerTabListeners(tab: HTMLElement, index: number): IDisposable { - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; const handleClickOrTouch = (e: MouseEvent | GestureEvent): void => { tab.blur(); @@ -506,16 +507,16 @@ export class TabsTitleControl extends TitleControl { }; // Open on Click / Touch - disposables.add(addDisposableListener(tab, EventType.MOUSE_DOWN, (e: MouseEvent) => handleClickOrTouch(e))); - disposables.add(addDisposableListener(tab, TouchEventType.Tap, (e: GestureEvent) => handleClickOrTouch(e))); + disposables.push(addDisposableListener(tab, EventType.MOUSE_DOWN, (e: MouseEvent) => handleClickOrTouch(e))); + disposables.push(addDisposableListener(tab, TouchEventType.Tap, (e: GestureEvent) => handleClickOrTouch(e))); // Touch Scroll Support - disposables.add(addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => { + disposables.push(addDisposableListener(tab, TouchEventType.Change, (e: GestureEvent) => { this.tabsScrollbar.setScrollPosition({ scrollLeft: this.tabsScrollbar.getScrollPosition().scrollLeft - e.translationX }); })); // Close on mouse middle click - disposables.add(addDisposableListener(tab, EventType.MOUSE_UP, (e: MouseEvent) => { + disposables.push(addDisposableListener(tab, EventType.MOUSE_UP, (e: MouseEvent) => { EventHelper.stop(e); tab.blur(); @@ -529,7 +530,7 @@ export class TabsTitleControl extends TitleControl { })); // Context menu on Shift+F10 - disposables.add(addDisposableListener(tab, EventType.KEY_DOWN, (e: KeyboardEvent) => { + disposables.push(addDisposableListener(tab, EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); if (event.shiftKey && event.keyCode === KeyCode.F10) { showContextMenu(e); @@ -537,12 +538,12 @@ export class TabsTitleControl extends TitleControl { })); // Context menu on touch context menu gesture - disposables.add(addDisposableListener(tab, TouchEventType.Contextmenu, (e: GestureEvent) => { + disposables.push(addDisposableListener(tab, TouchEventType.Contextmenu, (e: GestureEvent) => { showContextMenu(e); })); // Keyboard accessibility - disposables.add(addDisposableListener(tab, EventType.KEY_UP, (e: KeyboardEvent) => { + disposables.push(addDisposableListener(tab, EventType.KEY_UP, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); let handled = false; @@ -587,14 +588,14 @@ export class TabsTitleControl extends TitleControl { })); // Pin on double click - disposables.add(addDisposableListener(tab, EventType.DBLCLICK, (e: MouseEvent) => { + disposables.push(addDisposableListener(tab, EventType.DBLCLICK, (e: MouseEvent) => { EventHelper.stop(e); this.group.pinEditor(this.group.getEditor(index) || undefined); })); // Context menu - disposables.add(addDisposableListener(tab, EventType.CONTEXT_MENU, (e: Event) => { + disposables.push(addDisposableListener(tab, EventType.CONTEXT_MENU, (e: Event) => { EventHelper.stop(e, true); const input = this.group.getEditor(index); @@ -604,7 +605,7 @@ export class TabsTitleControl extends TitleControl { }, true /* use capture to fix https://github.com/Microsoft/vscode/issues/19145 */)); // Drag support - disposables.add(addDisposableListener(tab, EventType.DRAG_START, (e: DragEvent) => { + disposables.push(addDisposableListener(tab, EventType.DRAG_START, (e: DragEvent) => { const editor = this.group.getEditor(index); if (!editor) { return; @@ -626,7 +627,7 @@ export class TabsTitleControl extends TitleControl { })); // Drop support - disposables.add(new DragAndDropObserver(tab, { + disposables.push(new DragAndDropObserver(tab, { onDragEnter: e => { // Update class to signal drag operation @@ -679,7 +680,7 @@ export class TabsTitleControl extends TitleControl { } })); - return disposables; + return combinedDisposable(disposables); } private isSupportedDropTransfer(e: DragEvent): boolean { @@ -720,10 +721,10 @@ export class TabsTitleControl extends TitleControl { element.style.outlineColor = activeContrastBorderColor; element.style.outlineOffset = isTab ? '-5px' : '-3px'; } else { - element.style.outlineWidth = ''; - element.style.outlineStyle = ''; - element.style.outlineColor = activeContrastBorderColor || ''; - element.style.outlineOffset = ''; + element.style.outlineWidth = null; + element.style.outlineStyle = null; + element.style.outlineColor = activeContrastBorderColor; + element.style.outlineOffset = null; } // {{SQL CARBON EDIT}} -- Display the editor's tab color @@ -871,7 +872,7 @@ export class TabsTitleControl extends TitleControl { // Borders / Outline const borderRightColor = (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)); tabContainer.style.borderRight = borderRightColor ? `1px solid ${borderRightColor}` : null; - tabContainer.style.outlineColor = this.getColor(activeContrastBorder) || ''; + tabContainer.style.outlineColor = this.getColor(activeContrastBorder); // Settings const options = this.accessor.partOptions; @@ -929,7 +930,7 @@ export class TabsTitleControl extends TitleControl { // Container addClass(tabContainer, 'active'); tabContainer.setAttribute('aria-selected', 'true'); - tabContainer.style.backgroundColor = this.getColor(isGroupActive ? TAB_ACTIVE_BACKGROUND : TAB_UNFOCUSED_ACTIVE_BACKGROUND); + tabContainer.style.backgroundColor = this.getColor(TAB_ACTIVE_BACKGROUND); const activeTabBorderColorBottom = this.getColor(isGroupActive ? TAB_ACTIVE_BORDER : TAB_UNFOCUSED_ACTIVE_BORDER); if (activeTabBorderColorBottom) { @@ -1295,29 +1296,35 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { adjustedTabDragBackground = editorGroupHeaderTabsBackground.flatten(editorBackgroundColor, editorDragAndDropBackground, editorBackgroundColor, workbenchBackground); } - // Adjust gradient for focused and unfocused hover background - const makeTabHoverBackgroundRule = (color: Color, colorDrag: Color, hasFocus = false) => ` - .monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { - background: linear-gradient(to left, ${color}, transparent) !important; - } - - .monaco-workbench .part.editor > .content.dragged-over .editor-group-container${hasFocus ? '.active' : ''} > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { - background: linear-gradient(to left, ${colorDrag}, transparent) !important; - } - `; - // Adjust gradient for (focused) hover background if (tabHoverBackground && adjustedTabBackground && adjustedTabDragBackground) { const adjustedColor = tabHoverBackground.flatten(adjustedTabBackground); const adjustedColorDrag = tabHoverBackground.flatten(adjustedTabDragBackground); - collector.addRule(makeTabHoverBackgroundRule(adjustedColor, adjustedColorDrag, true)); + collector.addRule(` + .monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { + background: linear-gradient(to left, ${adjustedColor}, transparent) !important; + } + + + .monaco-workbench .part.editor > .content.dragged-over .editor-group-container.active > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { + background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important; + } + `); } // Adjust gradient for unfocused hover background if (tabUnfocusedHoverBackground && adjustedTabBackground && adjustedTabDragBackground) { const adjustedColor = tabUnfocusedHoverBackground.flatten(adjustedTabBackground); const adjustedColorDrag = tabUnfocusedHoverBackground.flatten(adjustedTabDragBackground); - collector.addRule(makeTabHoverBackgroundRule(adjustedColor, adjustedColorDrag)); + collector.addRule(` + .monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { + background: linear-gradient(to left, ${adjustedColor}, transparent) !important; + } + + .monaco-workbench .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink:not(.dragged):hover > .tab-label::after { + background: linear-gradient(to left, ${adjustedColorDrag}, transparent) !important; + } + `); } // Adjust gradient for drag and drop background @@ -1331,31 +1338,20 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { `); } - // Adjust gradient for active tab background (focused and unfocused editor groups) - const makeTabActiveBackgroundRule = (color: Color, colorDrag: Color, hasFocus = false) => ` - .monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container${hasFocus ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after { - background: linear-gradient(to left, ${color}, transparent); - } - - .monaco-workbench .part.editor > .content.dragged-over .editor-group-container${hasFocus ? '.active' : ':not(.active)'} > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after { - background: linear-gradient(to left, ${colorDrag}, transparent); - } - `; - - // Adjust gradient for unfocused active tab background + // Adjust gradient for active tab background const tabActiveBackground = theme.getColor(TAB_ACTIVE_BACKGROUND); if (tabActiveBackground && adjustedTabBackground && adjustedTabDragBackground) { const adjustedColor = tabActiveBackground.flatten(adjustedTabBackground); const adjustedColorDrag = tabActiveBackground.flatten(adjustedTabDragBackground); - collector.addRule(makeTabActiveBackgroundRule(adjustedColor, adjustedColorDrag, true)); - } + collector.addRule(` + .monaco-workbench .part.editor > .content:not(.dragged-over) .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after { + background: linear-gradient(to left, ${adjustedColor}, transparent); + } - // Adjust gradient for unfocused active tab background - const tabUnfocusedActiveBackground = theme.getColor(TAB_UNFOCUSED_ACTIVE_BACKGROUND); - if (tabUnfocusedActiveBackground && adjustedTabBackground && adjustedTabDragBackground) { - const adjustedColor = tabUnfocusedActiveBackground.flatten(adjustedTabBackground); - const adjustedColorDrag = tabUnfocusedActiveBackground.flatten(adjustedTabDragBackground); - collector.addRule(makeTabActiveBackgroundRule(adjustedColor, adjustedColorDrag)); + .monaco-workbench .part.editor > .content.dragged-over .editor-group-container > .title .tabs-container > .tab.sizing-shrink.active:not(.dragged) > .tab-label::after { + background: linear-gradient(to left, ${adjustedColorDrag}, transparent); + } + `); } // Adjust gradient for inactive tab background diff --git a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts index 9110ced6a3..155fa3c38e 100644 --- a/src/vs/workbench/browser/parts/editor/textResourceEditor.ts +++ b/src/vs/workbench/browser/parts/editor/textResourceEditor.ts @@ -70,7 +70,7 @@ export class AbstractTextResourceEditor extends BaseTextEditor { // Assert Model instance if (!(resolvedModel instanceof BaseTextEditorModel)) { - throw new Error('Unable to open file as text'); + return Promise.reject(new Error('Unable to open file as text')); } // Set Editor Model diff --git a/src/vs/workbench/browser/parts/editor/titleControl.ts b/src/vs/workbench/browser/parts/editor/titleControl.ts index 9d98b4d55c..1cc53647f0 100644 --- a/src/vs/workbench/browser/parts/editor/titleControl.ts +++ b/src/vs/workbench/browser/parts/editor/titleControl.ts @@ -18,7 +18,7 @@ import { localize } from 'vs/nls'; import { createActionViewItem, fillInActionBarActions, fillInContextMenuActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { ExecuteCommandAction, IMenu, IMenuService, MenuId } from 'vs/platform/actions/common/actions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -33,7 +33,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { BreadcrumbsControl, IBreadcrumbsControlOptions } from 'vs/workbench/browser/parts/editor/breadcrumbsControl'; import { EDITOR_TITLE_HEIGHT, IEditorGroupsAccessor, IEditorGroupView } from 'vs/workbench/browser/parts/editor/editor'; -import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor, EditorPinnedContext } from 'vs/workbench/common/editor'; +import { EditorCommandsContextActionRunner, IEditorCommandsContext, IEditorInput, toResource, IEditorPartOptions, SideBySideEditor } from 'vs/workbench/common/editor'; import { ResourceContextKey } from 'vs/workbench/common/resources'; import { Themable } from 'vs/workbench/common/theme'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; @@ -59,8 +59,6 @@ export abstract class TitleControl extends Themable { protected editorActionsToolbar: ToolBar; private resourceContext: ResourceContextKey; - private editorPinnedContext: IContextKey; - private editorToolBarMenuDisposables: IDisposable[] = []; private contextMenu: IMenu; @@ -87,8 +85,6 @@ export abstract class TitleControl extends Themable { super(themeService); this.resourceContext = this._register(instantiationService.createInstance(ResourceContextKey)); - this.editorPinnedContext = EditorPinnedContext.bindTo(contextKeyService); - this.contextMenu = this._register(this.menuService.createMenu(MenuId.EditorTitleContext, this.contextKeyService)); this.create(parent); @@ -225,9 +221,8 @@ export abstract class TitleControl extends Themable { // Dispose previous listeners this.editorToolBarMenuDisposables = dispose(this.editorToolBarMenuDisposables); - // Update contexts + // Update the resource context this.resourceContext.set(this.group.activeEditor ? withUndefinedAsNull(toResource(this.group.activeEditor, { supportSideBySide: SideBySideEditor.MASTER })) : null); - this.editorPinnedContext.set(this.group.activeEditor ? this.group.isPinned(this.group.activeEditor) : false); // Editor actions require the editor control to be there, so we retrieve it via service const activeControl = this.group.activeControl; @@ -292,11 +287,9 @@ export abstract class TitleControl extends Themable { protected onContextMenu(editor: IEditorInput, e: Event, node: HTMLElement): void { - // Update contexts based on editor picked and remember previous to restore - const currentResourceContext = this.resourceContext.get(); + // Update the resource context + const currentContext = this.resourceContext.get(); this.resourceContext.set(withUndefinedAsNull(toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }))); - const currentPinnedContext = !!this.editorPinnedContext.get(); - this.editorPinnedContext.set(this.group.isPinned(editor)); // Find target anchor let anchor: HTMLElement | { x: number, y: number } = node; @@ -317,9 +310,8 @@ export abstract class TitleControl extends Themable { getKeyBinding: (action) => this.getKeybinding(action), onHide: () => { - // restore previous contexts - this.resourceContext.set(currentResourceContext || null); - this.editorPinnedContext.set(currentPinnedContext); + // restore previous context + this.resourceContext.set(currentContext || null); // restore focus to active group this.accessor.activeGroup.focus(); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts index d30922211b..ae4a58bdb2 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsActions.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsActions.ts @@ -121,12 +121,12 @@ export class ConfigureNotificationAction extends Action { constructor( id: string, label: string, - private readonly _configurationActions: ReadonlyArray + private _configurationActions: IAction[] ) { super(id, label, 'configure-notification-action'); } - get configurationActions(): ReadonlyArray { + get configurationActions(): IAction[] { return this._configurationActions; } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index c91720b6a7..50a1a61a8d 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -219,7 +219,7 @@ export class NotificationsList extends Themable { this.listContainer.style.background = background ? background.toString() : null; const outlineColor = this.getColor(contrastBorder); - this.listContainer.style.outlineColor = outlineColor ? outlineColor.toString() : ''; + this.listContainer.style.outlineColor = outlineColor ? outlineColor.toString() : null; } } diff --git a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts index 7ef2e80223..98c250d6a1 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsStatus.ts @@ -3,20 +3,16 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem, IStatusMessageChangeEvent, StatusMessageChangeType, IStatusMessageViewItem } from 'vs/workbench/common/notifications'; +import { INotificationsModel, INotificationChangeEvent, NotificationChangeType, INotificationViewItem } from 'vs/workbench/common/notifications'; import { IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { HIDE_NOTIFICATIONS_CENTER, SHOW_NOTIFICATIONS_CENTER } from 'vs/workbench/browser/parts/notifications/notificationsCommands'; import { localize } from 'vs/nls'; export class NotificationsStatus extends Disposable { - - private notificationsCenterStatusItem: IStatusbarEntryAccessor; - private currentNotifications = new Set(); - - private currentStatusMessage: [IStatusMessageViewItem, IDisposable] | undefined; - + private statusItem: IStatusbarEntryAccessor; private isNotificationsCenterVisible: boolean; + private _counter: Set; constructor( private model: INotificationsModel, @@ -24,18 +20,29 @@ export class NotificationsStatus extends Disposable { ) { super(); - this.updateNotificationsCenterStatusItem(); + this._counter = new Set(); - if (model.statusMessage) { - this.doSetStatusMessage(model.statusMessage); - } + this.updateNotificationsStatusItem(); this.registerListeners(); } + private get count(): number { + return this._counter.size; + } + + update(isCenterVisible: boolean): void { + if (this.isNotificationsCenterVisible !== isCenterVisible) { + this.isNotificationsCenterVisible = isCenterVisible; + + // Showing the notification center resets the counter to 0 + this._counter.clear(); + this.updateNotificationsStatusItem(); + } + } + private registerListeners(): void { this._register(this.model.onDidNotificationChange(e => this.onDidNotificationChange(e))); - this._register(this.model.onDidStatusMessageChange(e => this.onDidStatusMessageChange(e))); } private onDidNotificationChange(e: INotificationChangeEvent): void { @@ -45,29 +52,29 @@ export class NotificationsStatus extends Disposable { // Notification got Added if (e.kind === NotificationChangeType.ADD) { - this.currentNotifications.add(e.item); + this._counter.add(e.item); } // Notification got Removed else if (e.kind === NotificationChangeType.REMOVE) { - this.currentNotifications.delete(e.item); + this._counter.delete(e.item); } - this.updateNotificationsCenterStatusItem(); + this.updateNotificationsStatusItem(); } - private updateNotificationsCenterStatusItem(): void { + private updateNotificationsStatusItem(): void { const statusProperties: IStatusbarEntry = { - text: this.currentNotifications.size === 0 ? '$(bell)' : `$(bell) ${this.currentNotifications.size}`, + text: this.count === 0 ? '$(bell)' : `$(bell) ${this.count}`, command: this.isNotificationsCenterVisible ? HIDE_NOTIFICATIONS_CENTER : SHOW_NOTIFICATIONS_CENTER, tooltip: this.getTooltip(), showBeak: this.isNotificationsCenterVisible }; - if (!this.notificationsCenterStatusItem) { - this.notificationsCenterStatusItem = this.statusbarService.addEntry(statusProperties, 'status.notifications', localize('status.notifications', "Notifications"), StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */); + if (!this.statusItem) { + this.statusItem = this.statusbarService.addEntry(statusProperties, StatusbarAlignment.RIGHT, -1000 /* towards the far end of the right hand side */); } else { - this.notificationsCenterStatusItem.update(statusProperties); + this.statusItem.update(statusProperties); } } @@ -80,96 +87,14 @@ export class NotificationsStatus extends Disposable { return localize('zeroNotifications', "No Notifications"); } - if (this.currentNotifications.size === 0) { + if (this.count === 0) { return localize('noNotifications', "No New Notifications"); } - if (this.currentNotifications.size === 1) { + if (this.count === 1) { return localize('oneNotification', "1 New Notification"); } - return localize('notifications', "{0} New Notifications", this.currentNotifications.size); - } - - update(isCenterVisible: boolean): void { - if (this.isNotificationsCenterVisible !== isCenterVisible) { - this.isNotificationsCenterVisible = isCenterVisible; - - // Showing the notification center resets the counter to 0 - this.currentNotifications.clear(); - this.updateNotificationsCenterStatusItem(); - } - } - - private onDidStatusMessageChange(e: IStatusMessageChangeEvent): void { - const statusItem = e.item; - - switch (e.kind) { - - // Show status notification - case StatusMessageChangeType.ADD: - this.doSetStatusMessage(statusItem); - - break; - - // Hide status notification (if its still the current one) - case StatusMessageChangeType.REMOVE: - if (this.currentStatusMessage && this.currentStatusMessage[0] === statusItem) { - dispose(this.currentStatusMessage[1]); - this.currentStatusMessage = undefined; - } - - break; - } - } - - private doSetStatusMessage(item: IStatusMessageViewItem): void { - const message = item.message; - - const showAfter = item.options && typeof item.options.showAfter === 'number' ? item.options.showAfter : 0; - const hideAfter = item.options && typeof item.options.hideAfter === 'number' ? item.options.hideAfter : -1; - - // Dismiss any previous - if (this.currentStatusMessage) { - dispose(this.currentStatusMessage[1]); - } - - // Create new - let statusMessageEntry: IStatusbarEntryAccessor; - let showHandle: any = setTimeout(() => { - statusMessageEntry = this.statusbarService.addEntry( - { text: message }, - 'status.message', - localize('status.message', "Status Message"), - StatusbarAlignment.LEFT, - -Number.MAX_VALUE /* far right on left hand side */ - ); - showHandle = null; - }, showAfter); - - // Dispose function takes care of timeouts and actual entry - let hideHandle: any; - const statusMessageDispose = { - dispose: () => { - if (showHandle) { - clearTimeout(showHandle); - } - - if (hideHandle) { - clearTimeout(hideHandle); - } - - if (statusMessageEntry) { - statusMessageEntry.dispose(); - } - } - }; - - if (hideAfter > 0) { - hideHandle = setTimeout(() => statusMessageDispose.dispose(), hideAfter); - } - - // Remember as current status message - this.currentStatusMessage = [item, statusMessageDispose]; + return localize('notifications', "{0} New Notifications", this.count); } } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/panel/panelActions.ts b/src/vs/workbench/browser/parts/panel/panelActions.ts index f52f265e4e..95f418625c 100644 --- a/src/vs/workbench/browser/parts/panel/panelActions.ts +++ b/src/vs/workbench/browser/parts/panel/panelActions.ts @@ -16,7 +16,6 @@ import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/ import { ActivityAction } from 'vs/workbench/browser/parts/compositeBarActions'; import { IActivity } from 'vs/workbench/common/activity'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ActivePanelContext, PanelPositionContext } from 'vs/workbench/common/panel'; export class ClosePanelAction extends Action { @@ -93,8 +92,8 @@ export class TogglePanelPositionAction extends Action { static readonly ID = 'workbench.action.togglePanelPosition'; static readonly LABEL = nls.localize('toggledPanelPosition', "Toggle Panel Position"); - static readonly MOVE_TO_RIGHT_LABEL = nls.localize('moveToRight', "Move Panel Right"); - static readonly MOVE_TO_BOTTOM_LABEL = nls.localize('moveToBottom', "Move Panel to Bottom"); + private static readonly MOVE_TO_RIGHT_LABEL = nls.localize('moveToRight', "Move Panel Right"); + private static readonly MOVE_TO_BOTTOM_LABEL = nls.localize('moveToBottom', "Move Panel to Bottom"); private toDispose: IDisposable[]; @@ -272,28 +271,16 @@ MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { group: '2_workbench_layout', command: { id: TogglePanelAction.ID, - title: nls.localize({ key: 'miShowPanel', comment: ['&& denotes a mnemonic'] }, "Show &&Panel"), - toggled: ActivePanelContext + title: nls.localize({ key: 'miTogglePanel', comment: ['&& denotes a mnemonic'] }, "Toggle &&Panel") }, order: 5 }); MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_workbench_layout_move', + group: '2_workbench_layout', command: { id: TogglePanelPositionAction.ID, - title: TogglePanelPositionAction.MOVE_TO_RIGHT_LABEL + title: TogglePanelPositionAction.LABEL }, - when: PanelPositionContext.isEqualTo('bottom'), - order: 5 -}); - -MenuRegistry.appendMenuItem(MenuId.MenubarAppearanceMenu, { - group: '3_workbench_layout_move', - command: { - id: TogglePanelPositionAction.ID, - title: TogglePanelPositionAction.MOVE_TO_BOTTOM_LABEL - }, - when: PanelPositionContext.isEqualTo('right'), - order: 5 + order: 3 }); diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index b66891317f..06803503dc 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -70,7 +70,7 @@ export class PanelPart extends CompositePart implements IPanelService { private panelFocusContextKey: IContextKey; private compositeBar: CompositeBar; - private compositeActions: Map = new Map(); + private compositeActions: { [compositeId: string]: { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction } } = Object.create(null); private blockOpeningPanel: boolean; private dimension: Dimension; @@ -245,7 +245,7 @@ export class PanelPart extends CompositePart implements IPanelService { .sort((p1, p2) => pinnedCompositeIds.indexOf(p1.id) - pinnedCompositeIds.indexOf(p2.id)); } - protected getActions(): ReadonlyArray { + protected getActions(): IAction[] { return [ this.instantiationService.createInstance(ToggleMaximizedPanelAction, ToggleMaximizedPanelAction.ID, ToggleMaximizedPanelAction.LABEL), this.instantiationService.createInstance(ClosePanelAction, ClosePanelAction.ID, ClosePanelAction.LABEL) @@ -261,11 +261,6 @@ export class PanelPart extends CompositePart implements IPanelService { } hideActivePanel(): void { - // First check if panel is visible and hide if so - if (this.layoutService.isVisible(Parts.PANEL_PART)) { - this.layoutService.setPanelHidden(true); - } - this.hideActiveComposite(); } @@ -316,14 +311,13 @@ export class PanelPart extends CompositePart implements IPanelService { } private getCompositeActions(compositeId: string): { activityAction: PanelActivityAction, pinnedAction: ToggleCompositePinnedAction } { - let compositeActions = this.compositeActions.get(compositeId); + let compositeActions = this.compositeActions[compositeId]; if (!compositeActions) { compositeActions = { activityAction: this.instantiationService.createInstance(PanelActivityAction, this.getPanel(compositeId)), pinnedAction: new ToggleCompositePinnedAction(this.getPanel(compositeId), this.compositeBar) }; - - this.compositeActions.set(compositeId, compositeActions); + this.compositeActions[compositeId] = compositeActions; } return compositeActions; @@ -331,11 +325,11 @@ export class PanelPart extends CompositePart implements IPanelService { protected removeComposite(compositeId: string): boolean { if (super.removeComposite(compositeId)) { - const compositeActions = this.compositeActions.get(compositeId); + const compositeActions = this.compositeActions[compositeId]; if (compositeActions) { compositeActions.activityAction.dispose(); compositeActions.pinnedAction.dispose(); - this.compositeActions.delete(compositeId); + delete this.compositeActions[compositeId]; } return true; diff --git a/src/vs/workbench/browser/parts/quickinput/quickInput.ts b/src/vs/workbench/browser/parts/quickinput/quickInput.ts index d884d522ce..fb53949b52 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInput.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInput.ts @@ -27,7 +27,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { Emitter, Event } from 'vs/base/common/event'; import { Button } from 'vs/base/browser/ui/button/button'; -import { dispose, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import Severity from 'vs/base/common/severity'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IContextKeyService, RawContextKey, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -97,7 +97,7 @@ type Visibilities = { customButton?: boolean; }; -class QuickInput extends Disposable implements IQuickInput { +class QuickInput implements IQuickInput { private _title: string; private _steps: number; @@ -109,17 +109,18 @@ class QuickInput extends Disposable implements IQuickInput { private _ignoreFocusOut = false; private _buttons: IQuickInputButton[] = []; private buttonsUpdated = false; - private readonly onDidTriggerButtonEmitter = this._register(new Emitter()); - private readonly onDidHideEmitter = this._register(new Emitter()); + private onDidTriggerButtonEmitter = new Emitter(); + private onDidHideEmitter = new Emitter(); - protected readonly visibleDisposables = this._register(new DisposableStore()); + protected visibleDisposables: IDisposable[] = []; + protected disposables: IDisposable[] = [ + this.onDidTriggerButtonEmitter, + this.onDidHideEmitter, + ]; private busyDelay: TimeoutTimer | null; - constructor( - protected ui: QuickInputUI - ) { - super(); + constructor(protected ui: QuickInputUI) { } get title() { @@ -201,7 +202,7 @@ class QuickInput extends Disposable implements IQuickInput { if (this.visible) { return; } - this.visibleDisposables.add( + this.visibleDisposables.push( this.ui.onDidTriggerButton(button => { if (this.buttons.indexOf(button) !== -1) { this.onDidTriggerButtonEmitter.fire(button); @@ -222,7 +223,7 @@ class QuickInput extends Disposable implements IQuickInput { didHide(): void { this.visible = false; - this.visibleDisposables.clear(); + this.visibleDisposables = dispose(this.visibleDisposables); this.onDidHideEmitter.fire(); } @@ -316,7 +317,7 @@ class QuickInput extends Disposable implements IQuickInput { public dispose(): void { this.hide(); - super.dispose(); + this.disposables = dispose(this.disposables); } } @@ -326,9 +327,9 @@ class QuickPick extends QuickInput implements IQuickPi private _value = ''; private _placeholder: string; - private readonly onDidChangeValueEmitter = this._register(new Emitter()); - private readonly onDidAcceptEmitter = this._register(new Emitter()); - private readonly onDidCustomEmitter = this._register(new Emitter()); + private onDidChangeValueEmitter = new Emitter(); + private onDidAcceptEmitter = new Emitter(); + private onDidCustomEmitter = new Emitter(); private _items: Array = []; private itemsUpdated = false; private _canSelectMany = false; @@ -339,12 +340,12 @@ class QuickPick extends QuickInput implements IQuickPi private _activeItems: T[] = []; private activeItemsUpdated = false; private activeItemsToConfirm: T[] | null = []; - private readonly onDidChangeActiveEmitter = this._register(new Emitter()); + private onDidChangeActiveEmitter = new Emitter(); private _selectedItems: T[] = []; private selectedItemsUpdated = false; private selectedItemsToConfirm: T[] | null = []; - private readonly onDidChangeSelectionEmitter = this._register(new Emitter()); - private readonly onDidTriggerItemButtonEmitter = this._register(new Emitter>()); + private onDidChangeSelectionEmitter = new Emitter(); + private onDidTriggerItemButtonEmitter = new Emitter>(); private _valueSelection: Readonly<[number, number]>; private valueSelectionUpdated = true; private _validationMessage: string; @@ -355,6 +356,17 @@ class QuickPick extends QuickInput implements IQuickPi quickNavigate: IQuickNavigateConfiguration; + constructor(ui: QuickInputUI) { + super(ui); + this.disposables.push( + this.onDidChangeValueEmitter, + this.onDidAcceptEmitter, + this.onDidCustomEmitter, + this.onDidChangeActiveEmitter, + this.onDidChangeSelectionEmitter, + this.onDidTriggerItemButtonEmitter, + ); + } get value() { return this._value; @@ -530,7 +542,7 @@ class QuickPick extends QuickInput implements IQuickPi show() { if (!this.visible) { - this.visibleDisposables.add( + this.visibleDisposables.push( this.ui.inputBox.onDidChange(value => { if (value === this.value) { return; @@ -539,104 +551,105 @@ class QuickPick extends QuickInput implements IQuickPi this.ui.list.filter(this.ui.inputBox.value); this.trySelectFirst(); this.onDidChangeValueEmitter.fire(value); - })); - this.visibleDisposables.add(this.ui.inputBox.onMouseDown(event => { - if (!this.autoFocusOnList) { - this.ui.list.clearFocus(); - } - })); - this.visibleDisposables.add(this.ui.inputBox.onKeyDown(event => { - switch (event.keyCode) { - case KeyCode.DownArrow: - this.ui.list.focus('Next'); - if (this.canSelectMany) { - this.ui.list.domFocus(); - } - event.preventDefault(); - break; - case KeyCode.UpArrow: - if (this.ui.list.getFocusedElements().length) { - this.ui.list.focus('Previous'); - } else { - this.ui.list.focus('Last'); - } - if (this.canSelectMany) { - this.ui.list.domFocus(); - } - event.preventDefault(); - break; - case KeyCode.PageDown: - if (this.ui.list.getFocusedElements().length) { - this.ui.list.focus('NextPage'); - } else { - this.ui.list.focus('First'); - } - if (this.canSelectMany) { - this.ui.list.domFocus(); - } - event.preventDefault(); - break; - case KeyCode.PageUp: - if (this.ui.list.getFocusedElements().length) { - this.ui.list.focus('PreviousPage'); - } else { - this.ui.list.focus('Last'); - } - if (this.canSelectMany) { - this.ui.list.domFocus(); - } - event.preventDefault(); - break; - } - })); - this.visibleDisposables.add(this.ui.onDidAccept(() => { - if (!this.canSelectMany && this.activeItems[0]) { - this._selectedItems = [this.activeItems[0]]; - this.onDidChangeSelectionEmitter.fire(this.selectedItems); - } - this.onDidAcceptEmitter.fire(undefined); - })); - this.visibleDisposables.add(this.ui.onDidCustom(() => { - this.onDidCustomEmitter.fire(undefined); - })); - this.visibleDisposables.add(this.ui.list.onDidChangeFocus(focusedItems => { - if (this.activeItemsUpdated) { - return; // Expect another event. - } - if (this.activeItemsToConfirm !== this._activeItems && equals(focusedItems, this._activeItems, (a, b) => a === b)) { - return; - } - this._activeItems = focusedItems as T[]; - this.onDidChangeActiveEmitter.fire(focusedItems as T[]); - })); - this.visibleDisposables.add(this.ui.list.onDidChangeSelection(selectedItems => { - if (this.canSelectMany) { - if (selectedItems.length) { - this.ui.list.setSelectedElements([]); + }), + this.ui.inputBox.onMouseDown(event => { + if (!this.autoFocusOnList) { + this.ui.list.clearFocus(); + } + }), + this.ui.inputBox.onKeyDown(event => { + switch (event.keyCode) { + case KeyCode.DownArrow: + this.ui.list.focus('Next'); + if (this.canSelectMany) { + this.ui.list.domFocus(); + } + event.preventDefault(); + break; + case KeyCode.UpArrow: + if (this.ui.list.getFocusedElements().length) { + this.ui.list.focus('Previous'); + } else { + this.ui.list.focus('Last'); + } + if (this.canSelectMany) { + this.ui.list.domFocus(); + } + event.preventDefault(); + break; + case KeyCode.PageDown: + if (this.ui.list.getFocusedElements().length) { + this.ui.list.focus('NextPage'); + } else { + this.ui.list.focus('First'); + } + if (this.canSelectMany) { + this.ui.list.domFocus(); + } + event.preventDefault(); + break; + case KeyCode.PageUp: + if (this.ui.list.getFocusedElements().length) { + this.ui.list.focus('PreviousPage'); + } else { + this.ui.list.focus('Last'); + } + if (this.canSelectMany) { + this.ui.list.domFocus(); + } + event.preventDefault(); + break; + } + }), + this.ui.onDidAccept(() => { + if (!this.canSelectMany && this.activeItems[0]) { + this._selectedItems = [this.activeItems[0]]; + this.onDidChangeSelectionEmitter.fire(this.selectedItems); } - return; - } - if (this.selectedItemsToConfirm !== this._selectedItems && equals(selectedItems, this._selectedItems, (a, b) => a === b)) { - return; - } - this._selectedItems = selectedItems as T[]; - this.onDidChangeSelectionEmitter.fire(selectedItems as T[]); - if (selectedItems.length) { this.onDidAcceptEmitter.fire(undefined); - } - })); - this.visibleDisposables.add(this.ui.list.onChangedCheckedElements(checkedItems => { - if (!this.canSelectMany) { - return; - } - if (this.selectedItemsToConfirm !== this._selectedItems && equals(checkedItems, this._selectedItems, (a, b) => a === b)) { - return; - } - this._selectedItems = checkedItems as T[]; - this.onDidChangeSelectionEmitter.fire(checkedItems as T[]); - })); - this.visibleDisposables.add(this.ui.list.onButtonTriggered(event => this.onDidTriggerItemButtonEmitter.fire(event as IQuickPickItemButtonEvent))); - this.visibleDisposables.add(this.registerQuickNavigation()); + }), + this.ui.onDidCustom(() => { + this.onDidCustomEmitter.fire(undefined); + }), + this.ui.list.onDidChangeFocus(focusedItems => { + if (this.activeItemsUpdated) { + return; // Expect another event. + } + if (this.activeItemsToConfirm !== this._activeItems && equals(focusedItems, this._activeItems, (a, b) => a === b)) { + return; + } + this._activeItems = focusedItems as T[]; + this.onDidChangeActiveEmitter.fire(focusedItems as T[]); + }), + this.ui.list.onDidChangeSelection(selectedItems => { + if (this.canSelectMany) { + if (selectedItems.length) { + this.ui.list.setSelectedElements([]); + } + return; + } + if (this.selectedItemsToConfirm !== this._selectedItems && equals(selectedItems, this._selectedItems, (a, b) => a === b)) { + return; + } + this._selectedItems = selectedItems as T[]; + this.onDidChangeSelectionEmitter.fire(selectedItems as T[]); + if (selectedItems.length) { + this.onDidAcceptEmitter.fire(undefined); + } + }), + this.ui.list.onChangedCheckedElements(checkedItems => { + if (!this.canSelectMany) { + return; + } + if (this.selectedItemsToConfirm !== this._selectedItems && equals(checkedItems, this._selectedItems, (a, b) => a === b)) { + return; + } + this._selectedItems = checkedItems as T[]; + this.onDidChangeSelectionEmitter.fire(checkedItems as T[]); + }), + this.ui.list.onButtonTriggered(event => this.onDidTriggerItemButtonEmitter.fire(event as IQuickPickItemButtonEvent)), + this.registerQuickNavigation() + ); this.valueSelectionUpdated = true; } super.show(); // TODO: Why have show() bubble up while update() trickles down? (Could move setComboboxAccessibility() here.) @@ -771,8 +784,16 @@ class InputBox extends QuickInput implements IInputBox { private _prompt: string; private noValidationMessage = InputBox.noPromptMessage; private _validationMessage: string; - private readonly onDidValueChangeEmitter = this._register(new Emitter()); - private readonly onDidAcceptEmitter = this._register(new Emitter()); + private onDidValueChangeEmitter = new Emitter(); + private onDidAcceptEmitter = new Emitter(); + + constructor(ui: QuickInputUI) { + super(ui); + this.disposables.push( + this.onDidValueChangeEmitter, + this.onDidAcceptEmitter, + ); + } get value() { return this._value; @@ -828,21 +849,22 @@ class InputBox extends QuickInput implements IInputBox { this.update(); } - readonly onDidChangeValue = this.onDidValueChangeEmitter.event; + onDidChangeValue = this.onDidValueChangeEmitter.event; - readonly onDidAccept = this.onDidAcceptEmitter.event; + onDidAccept = this.onDidAcceptEmitter.event; show() { if (!this.visible) { - this.visibleDisposables.add( + this.visibleDisposables.push( this.ui.inputBox.onDidChange(value => { if (value === this.value) { return; } this._value = value; this.onDidValueChangeEmitter.fire(value); - })); - this.visibleDisposables.add(this.ui.onDidAccept(() => this.onDidAcceptEmitter.fire(undefined))); + }), + this.ui.onDidAccept(() => this.onDidAcceptEmitter.fire(undefined)), + ); this.valueSelectionUpdated = true; } super.show(); @@ -898,10 +920,10 @@ export class QuickInputService extends Component implements IQuickInputService { private enabled = true; private inQuickOpenWidgets: Record = {}; private inQuickOpenContext: IContextKey; - private contexts: Map> = new Map(); - private readonly onDidAcceptEmitter = this._register(new Emitter()); - private readonly onDidCustomEmitter = this._register(new Emitter()); - private readonly onDidTriggerButtonEmitter = this._register(new Emitter()); + private contexts: { [id: string]: IContextKey; } = Object.create(null); + private onDidAcceptEmitter = this._register(new Emitter()); + private onDidCustomEmitter = this._register(new Emitter()); + private onDidTriggerButtonEmitter = this._register(new Emitter()); private keyMods: Writeable = { ctrlCmd: false, alt: false }; private controller: QuickInput | null = null; @@ -947,11 +969,11 @@ export class QuickInputService extends Component implements IQuickInputService { private setContextKey(id?: string) { let key: IContextKey | undefined; if (id) { - key = this.contexts.get(id); + key = this.contexts[id]; if (!key) { key = new RawContextKey(id, false) .bindTo(this.contextKeyService); - this.contexts.set(id, key); + this.contexts[id] = key; } } @@ -967,11 +989,11 @@ export class QuickInputService extends Component implements IQuickInputService { } private resetContextKeys() { - this.contexts.forEach(context => { - if (context.get()) { - context.reset(); + for (const key in this.contexts) { + if (this.contexts[key].get()) { + this.contexts[key].reset(); } - }); + } } private registerKeyModsListeners() { @@ -1106,9 +1128,6 @@ export class QuickInputService extends Component implements IQuickInputService { this.hide(true); } })); - this._register(dom.addDisposableListener(container, dom.EventType.FOCUS, (e: FocusEvent) => { - inputBox.setFocus(); - })); this._register(dom.addDisposableListener(container, dom.EventType.KEY_DOWN, (e: KeyboardEvent) => { const event = new StandardKeyboardEvent(e); switch (event.keyCode) { diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts b/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts index b680d30a83..5be7b6a539 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputBox.ts @@ -8,24 +8,25 @@ import * as dom from 'vs/base/browser/dom'; import { InputBox, IRange, MessageType } from 'vs/base/browser/ui/inputbox/inputBox'; import { inputBackground, inputForeground, inputBorder, inputValidationInfoBackground, inputValidationInfoForeground, inputValidationInfoBorder, inputValidationWarningBackground, inputValidationWarningForeground, inputValidationWarningBorder, inputValidationErrorBackground, inputValidationErrorForeground, inputValidationErrorBorder } from 'vs/platform/theme/common/colorRegistry'; import { ITheme } from 'vs/platform/theme/common/themeService'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import Severity from 'vs/base/common/severity'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; const $ = dom.$; -export class QuickInputBox extends Disposable { +export class QuickInputBox { private container: HTMLElement; private inputBox: InputBox; + private disposables: IDisposable[] = []; constructor( private parent: HTMLElement ) { - super(); this.container = dom.append(this.parent, $('.quick-input-box')); - this.inputBox = this._register(new InputBox(this.container, undefined)); + this.inputBox = new InputBox(this.container, undefined); + this.disposables.push(this.inputBox); } onKeyDown = (handler: (event: StandardKeyboardEvent) => void): IDisposable => { @@ -128,4 +129,8 @@ export class QuickInputBox extends Disposable { inputValidationErrorBorder: theme.getColor(inputValidationErrorBorder), }); } + + dispose() { + this.disposables = dispose(this.disposables); + } } diff --git a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts index f369c88653..07fdb8ef9e 100644 --- a/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts +++ b/src/vs/workbench/browser/parts/quickopen/quickOpenController.ts @@ -74,9 +74,9 @@ export class QuickOpenController extends Component implements IQuickOpenService private lastInputValue: string; private lastSubmittedInputValue: string; private quickOpenWidget: QuickOpenWidget; - private mapResolvedHandlersToPrefix: Map> = new Map(); - private mapContextKeyToContext: Map> = new Map(); - private handlerOnOpenCalled: Set = new Set(); + private mapResolvedHandlersToPrefix: { [prefix: string]: Promise; } = Object.create(null); + private mapContextKeyToContext: { [id: string]: IContextKey; } = Object.create(null); + private handlerOnOpenCalled: { [prefix: string]: boolean; } = Object.create(null); private promisesToCompleteOnHide: ValueCallback[] = []; private previousActiveHandlerDescriptor: QuickOpenHandlerDescriptor | null; private actionProvider = new ContributableActionProvider(); @@ -258,13 +258,13 @@ export class QuickOpenController extends Component implements IQuickOpenService this.cancelPendingGetResultsInvocation(); // Pass to handlers - this.mapResolvedHandlersToPrefix.forEach((promise, prefix) => { - promise.then(handler => { - this.handlerOnOpenCalled.delete(prefix); + for (let prefix in this.mapResolvedHandlersToPrefix) { + this.mapResolvedHandlersToPrefix[prefix].then(handler => { + this.handlerOnOpenCalled[prefix] = false; handler.onClose(reason === HideReason.CANCELED); // Don't check if onOpen was called to preserve old behaviour for now }); - }); + } // Complete promises that are waiting while (this.promisesToCompleteOnHide.length) { @@ -294,16 +294,16 @@ export class QuickOpenController extends Component implements IQuickOpenService } private resetQuickOpenContextKeys(): void { - this.mapContextKeyToContext.forEach(context => context.reset()); + Object.keys(this.mapContextKeyToContext).forEach(k => this.mapContextKeyToContext[k].reset()); } private setQuickOpenContextKey(id?: string): void { let key: IContextKey | undefined; if (id) { - key = this.mapContextKeyToContext.get(id); + key = this.mapContextKeyToContext[id]; if (!key) { key = new RawContextKey(id, false).bindTo(this.contextKeyService); - this.mapContextKeyToContext.set(id, key); + this.mapContextKeyToContext[id] = key; } } @@ -454,16 +454,14 @@ export class QuickOpenController extends Component implements IQuickOpenService const previousInput = this.quickOpenWidget.getInput(); const wasShowingHistory = previousInput && previousInput.entries && previousInput.entries.some(e => e instanceof EditorHistoryEntry || e instanceof EditorHistoryEntryGroup); if (wasShowingHistory || matchingHistoryEntries.length > 0) { - (async () => { - if (resolvedHandler.hasShortResponseTime()) { - await timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME); - } + if (resolvedHandler.hasShortResponseTime()) { + await timeout(QuickOpenController.MAX_SHORT_RESPONSE_TIME); + } - if (!token.isCancellationRequested && !inputSet) { - this.quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); - inputSet = true; - } - })(); + if (!token.isCancellationRequested && !inputSet) { + this.quickOpenWidget.setInput(quickOpenModel, { autoFocusFirstEntry: true }); + inputSet = true; + } } // Get results @@ -525,7 +523,7 @@ export class QuickOpenController extends Component implements IQuickOpenService const model = new QuickOpenModel([new PlaceholderQuickOpenEntry(placeHolderLabel)], this.actionProvider); this.showModel(model, resolvedHandler.getAutoFocus(value, { model, quickNavigateConfiguration: this.quickOpenWidget.getQuickNavigateConfiguration() }), types.withNullAsUndefined(resolvedHandler.getAriaLabel())); - return; + return Promise.resolve(undefined); } // Support extra class from handler @@ -581,45 +579,38 @@ export class QuickOpenController extends Component implements IQuickOpenService return mapEntryToPath; } - private async resolveHandler(handler: QuickOpenHandlerDescriptor): Promise { - let result = this.doResolveHandler(handler); + private resolveHandler(handler: QuickOpenHandlerDescriptor): Promise { + let result = this._resolveHandler(handler); const id = handler.getId(); - if (!this.handlerOnOpenCalled.has(id)) { + if (!this.handlerOnOpenCalled[id]) { const original = result; - this.handlerOnOpenCalled.add(id); - result = original.then(resolved => { - this.mapResolvedHandlersToPrefix.set(id, original); + this.handlerOnOpenCalled[id] = true; + result = this.mapResolvedHandlersToPrefix[id] = original.then(resolved => { + this.mapResolvedHandlersToPrefix[id] = original; resolved.onOpen(); return resolved; }); - - this.mapResolvedHandlersToPrefix.set(id, result); } - try { - return await result; - } catch (error) { - this.mapResolvedHandlersToPrefix.delete(id); + return result.then(null, (error) => { + delete this.mapResolvedHandlersToPrefix[id]; - throw new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`); - } + return Promise.reject(new Error(`Unable to instantiate quick open handler ${handler.getId()}: ${JSON.stringify(error)}`)); + }); } - private doResolveHandler(handler: QuickOpenHandlerDescriptor): Promise { + private _resolveHandler(handler: QuickOpenHandlerDescriptor): Promise { const id = handler.getId(); // Return Cached - if (this.mapResolvedHandlersToPrefix.has(id)) { - return this.mapResolvedHandlersToPrefix.get(id)!; + if (this.mapResolvedHandlersToPrefix[id]) { + return this.mapResolvedHandlersToPrefix[id]; } // Otherwise load and create - const result = Promise.resolve(handler.instantiate(this.instantiationService)); - this.mapResolvedHandlersToPrefix.set(id, result); - - return result; + return this.mapResolvedHandlersToPrefix[id] = Promise.resolve(handler.instantiate(this.instantiationService)); } layout(dimension: Dimension): void { diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 8098f4e4af..ed5644728e 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -191,7 +191,7 @@ export class SidebarPart extends CompositePart implements IViewletServi async openViewlet(id: string | undefined, focus?: boolean): Promise { if (typeof id === 'string' && this.getViewlet(id)) { - return this.doOpenViewlet(id, focus); + return Promise.resolve(this.doOpenViewlet(id, focus)); } await this.extensionService.whenInstalledExtensionsRegistered(); diff --git a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css index 4753dfb10f..9a7130125d 100644 --- a/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css +++ b/src/vs/workbench/browser/parts/statusbar/media/statusbarpart.css @@ -9,35 +9,20 @@ width: 100%; height: 22px; font-size: 12px; - display: flex; } -.monaco-workbench .part.statusbar > .left-items, -.monaco-workbench .part.statusbar > .right-items { - display: flex; - flex-wrap: wrap; /* individual entries should not shrink since we do not control their content */ -} - -.monaco-workbench .part.statusbar > .right-items { - flex-direction: row-reverse; /* ensures that the most right elements wrap last when space is little */ -} - -.monaco-workbench .part.statusbar > .left-items { - flex-grow: 1; /* left items push right items to the far right end */ -} - -.monaco-workbench .part.statusbar > .items-container > .statusbar-item { +.monaco-workbench .part.statusbar > .statusbar-item { display: inline-block; line-height: 22px; height: 100%; vertical-align: top; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak { +.monaco-workbench .part.statusbar > .statusbar-item.has-beak { position: relative; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { +.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { content: ''; position: absolute; left: 11px; @@ -48,54 +33,66 @@ border-right: 5px solid transparent; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item > :first-child { +.monaco-workbench .part.statusbar > .statusbar-item.left > :first-child, +.monaco-workbench .part.statusbar > .statusbar-item.right > :first-child +{ margin-right: 3px; margin-left: 3px; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.left.first-visible-item { - padding-left: 7px; /* Add padding to the most left status bar item */ +.monaco-workbench .part.statusbar > .statusbar-item.right { + float: right; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.right.last-visible-item { - padding-right: 7px; /* Add padding to the most right status bar item */ +/* adding padding to the most left status bar item */ +.monaco-workbench .part.statusbar > .statusbar-item.left:first-child, +.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.left { + padding-left: 7px; +} + +/* adding padding to the most right status bar item */ +.monaco-workbench .part.statusbar > .statusbar-item.right:first-child { + padding-right: 7px; } /* tweak appearance for items with background to improve hover feedback */ -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-background-color.left.first-visible-item, -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-background-color.right.last-visible-item { +.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left:first-child, +.monaco-workbench .part.statusbar > .statusbar-item.right + .statusbar-item.has-background-color.left, +.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right:first-child { padding-right: 0; padding-left: 0; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-background-color > :first-child { +.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.left > :first-child, +.monaco-workbench .part.statusbar > .statusbar-item.has-background-color.right > :first-child +{ margin-right: 0; margin-left: 0; padding-left: 10px; padding-right: 10px; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item a { +.monaco-workbench .part.statusbar > .statusbar-item a { cursor: pointer; display: inline-block; height: 100%; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > span { +.monaco-workbench .part.statusbar > .statusbar-entry > span { height: 100%; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > span, -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry > a { +.monaco-workbench .part.statusbar > .statusbar-entry > span, +.monaco-workbench .part.statusbar > .statusbar-entry > a { padding: 0 5px 0 5px; white-space: pre; /* gives some degree of styling */ } -.monaco-workbench .part.statusbar > .items-container > .statusbar-entry span.octicon { +.monaco-workbench .part.statusbar > .statusbar-entry span.octicon { text-align: center; font-size: 14px; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item a:hover { +.monaco-workbench .part.statusbar > .statusbar-item a:hover { text-decoration: none; } \ No newline at end of file diff --git a/src/vs/workbench/browser/parts/statusbar/statusbar.ts b/src/vs/workbench/browser/parts/statusbar/statusbar.ts index e0151a876d..77b24eb01f 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbar.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbar.ts @@ -14,21 +14,11 @@ export interface IStatusbarItem { } export class StatusbarItemDescriptor { - readonly syncDescriptor: SyncDescriptor0; - readonly id: string; - readonly name: string; - readonly alignment: StatusbarAlignment; - readonly priority: number; + syncDescriptor: SyncDescriptor0; + alignment: StatusbarAlignment; + priority: number; - constructor( - ctor: IConstructorSignature0, - id: string, - name: string, - alignment?: StatusbarAlignment, - priority?: number - ) { - this.id = id; - this.name = name; + constructor(ctor: IConstructorSignature0, alignment?: StatusbarAlignment, priority?: number) { this.syncDescriptor = createSyncDescriptor(ctor); this.alignment = alignment || StatusbarAlignment.LEFT; this.priority = priority || 0; @@ -36,16 +26,21 @@ export class StatusbarItemDescriptor { } export interface IStatusbarRegistry { - - readonly items: StatusbarItemDescriptor[]; - registerStatusbarItem(descriptor: StatusbarItemDescriptor): void; + items: StatusbarItemDescriptor[]; } class StatusbarRegistry implements IStatusbarRegistry { - private readonly _items: StatusbarItemDescriptor[] = []; - get items(): StatusbarItemDescriptor[] { return this._items; } + private _items: StatusbarItemDescriptor[]; + + constructor() { + this._items = []; + } + + get items(): StatusbarItemDescriptor[] { + return this._items; + } registerStatusbarItem(descriptor: StatusbarItemDescriptor): void { this._items.push(descriptor); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index b57445d7ab..b54df672bc 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/statusbarpart'; import * as nls from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { dispose, IDisposable, Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable, Disposable } from 'vs/base/common/lifecycle'; import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { Registry } from 'vs/platform/registry/common/platform'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -17,308 +17,28 @@ import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiat import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { Action, IAction } from 'vs/base/common/actions'; +import { Action } from 'vs/base/common/actions'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector, ThemeColor } from 'vs/platform/theme/common/themeService'; import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_ITEM_ACTIVE_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_FOREGROUND, STATUS_BAR_PROMINENT_ITEM_BACKGROUND, STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER } from 'vs/workbench/common/theme'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { isThemeColor } from 'vs/editor/common/editorCommon'; import { Color } from 'vs/base/common/color'; -import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass, EventType, hide, show, removeClasses } from 'vs/base/browser/dom'; +import { addClass, EventHelper, createStyleSheet, addDisposableListener, addClasses, clearNode, removeClass } from 'vs/base/browser/dom'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IStorageService, StorageScope, IWorkspaceStorageChangeEvent } from 'vs/platform/storage/common/storage'; +import { IStorageService } from 'vs/platform/storage/common/storage'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { coalesce } from 'vs/base/common/arrays'; -import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; -import { ToggleStatusbarVisibilityAction } from 'vs/workbench/browser/actions/layoutActions'; -import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; -import { values } from 'vs/base/common/map'; -interface IPendingStatusbarEntry { - id: string; - name: string; - entry: IStatusbarEntry; - alignment: StatusbarAlignment; - priority: number; - accessor?: IStatusbarEntryAccessor; -} - -interface IStatusbarViewModelEntry { - id: string; - name: string; - alignment: StatusbarAlignment; - priority: number; - container: HTMLElement; -} - -class StatusbarViewModel extends Disposable { - - private static readonly HIDDEN_ENTRIES_KEY = 'workbench.statusbar.hidden'; - - private readonly _entries: IStatusbarViewModelEntry[] = []; - get entries(): IStatusbarViewModelEntry[] { return this._entries; } - - private hidden: Set; - - constructor(private storageService: IStorageService) { - super(); - - this.restoreState(); - this.registerListeners(); - } - - private restoreState(): void { - const hiddenRaw = this.storageService.get(StatusbarViewModel.HIDDEN_ENTRIES_KEY, StorageScope.GLOBAL); - if (hiddenRaw) { - try { - const hiddenArray: string[] = JSON.parse(hiddenRaw); - this.hidden = new Set(hiddenArray); - } catch (error) { - // ignore parsing errors - } - } - - if (!this.hidden) { - this.hidden = new Set(); - } - } - - private registerListeners(): void { - this._register(this.storageService.onDidChangeStorage(e => this.onDidStorageChange(e))); - } - - private onDidStorageChange(event: IWorkspaceStorageChangeEvent): void { - if (event.key === StatusbarViewModel.HIDDEN_ENTRIES_KEY && event.scope === StorageScope.GLOBAL) { - - // Keep current hidden entries - const currentlyHidden = new Set(this.hidden); - - // Load latest state of hidden entries - this.hidden.clear(); - this.restoreState(); - - const changed = new Set(); - - // Check for each entry that is now visible - currentlyHidden.forEach(id => { - if (!this.hidden.has(id)) { - changed.add(id); - } - }); - - // Check for each entry that is now hidden - this.hidden.forEach(id => { - if (!currentlyHidden.has(id)) { - changed.add(id); - } - }); - - // Update visibility for entries have changed - if (changed.size > 0) { - this._entries.forEach(entry => { - if (changed.has(entry.id)) { - this.updateVisibility(entry.id); - - changed.delete(entry.id); - } - }); - } - } - } - - add(entry: IStatusbarViewModelEntry): IDisposable { - this._entries.push(entry); // intentionally not using a map here since multiple entries can have the same ID! - - // Update visibility directly - this.updateVisibility(entry); - - // Sort according to priority - this.sort(); - - // Mark first/last visible entry - this.markFirstLastVisibleEntry(); - - return toDisposable(() => this.remove(entry)); - } - - private remove(entry: IStatusbarViewModelEntry): void { - const index = this._entries.indexOf(entry); - if (index >= 0) { - this._entries.splice(index, 1); - - // Mark first/last visible entry - this.markFirstLastVisibleEntry(); - } - } - - isHidden(id: string): boolean { - return this.hidden.has(id); - } - - hide(id: string): void { - if (!this.hidden.has(id)) { - this.hidden.add(id); - - this.updateVisibility(id); - - this.saveState(); - } - } - - show(id: string): void { - if (this.hidden.has(id)) { - this.hidden.delete(id); - - this.updateVisibility(id); - - this.saveState(); - } - } - - findEntry(container: HTMLElement): IStatusbarViewModelEntry | undefined { - for (const entry of this._entries) { - if (entry.container === container) { - return entry; - } - } - - return undefined; - } - - getEntries(alignment: StatusbarAlignment): IStatusbarViewModelEntry[] { - return this._entries.filter(entry => entry.alignment === alignment); - } - - private updateVisibility(id: string): void; - private updateVisibility(entry: IStatusbarViewModelEntry): void; - private updateVisibility(arg1: string | IStatusbarViewModelEntry): void { - - // By identifier - if (typeof arg1 === 'string') { - const id = arg1; - - for (const entry of this._entries) { - if (entry.id === id) { - this.updateVisibility(entry); - } - } - } - - // By entry - else { - const entry = arg1; - const isHidden = this.isHidden(entry.id); - - // Use CSS to show/hide item container - if (isHidden) { - hide(entry.container); - } else { - show(entry.container); - } - - // Mark first/last visible entry - this.markFirstLastVisibleEntry(); - } - } - - private saveState(): void { - if (this.hidden.size > 0) { - this.storageService.store(StatusbarViewModel.HIDDEN_ENTRIES_KEY, JSON.stringify(values(this.hidden)), StorageScope.GLOBAL); - } else { - this.storageService.remove(StatusbarViewModel.HIDDEN_ENTRIES_KEY, StorageScope.GLOBAL); - } - } - - private sort(): void { - this._entries.sort((entryA, entryB) => { - if (entryA.alignment === entryB.alignment) { - return entryB.priority - entryA.priority; // higher priority towards the left - } - - if (entryA.alignment === StatusbarAlignment.LEFT) { - return -1; - } - - if (entryB.alignment === StatusbarAlignment.LEFT) { - return 1; - } - - return 0; - }); - } - - private markFirstLastVisibleEntry(): void { - this.doMarkFirstLastVisibleStatusbarItem(this.getEntries(StatusbarAlignment.LEFT)); - this.doMarkFirstLastVisibleStatusbarItem(this.getEntries(StatusbarAlignment.RIGHT)); - } - - private doMarkFirstLastVisibleStatusbarItem(entries: IStatusbarViewModelEntry[]): void { - let firstVisibleItem: IStatusbarViewModelEntry | undefined; - let lastVisibleItem: IStatusbarViewModelEntry | undefined; - - for (const entry of entries) { - - // Clear previous first - removeClasses(entry.container, 'first-visible-item', 'last-visible-item'); - - const isVisible = !this.isHidden(entry.id); - if (isVisible) { - if (!firstVisibleItem) { - firstVisibleItem = entry; - } - - lastVisibleItem = entry; - } - } - - // Mark: first visible item - if (firstVisibleItem) { - addClass(firstVisibleItem.container, 'first-visible-item'); - } - - // Mark: last visible item - if (lastVisibleItem) { - addClass(lastVisibleItem.container, 'last-visible-item'); - } - } -} - -class ToggleStatusbarEntryVisibilityAction extends Action { - - constructor(id: string, label: string, private model: StatusbarViewModel) { - super(id, label, undefined, true); - - this.checked = !model.isHidden(id); - } - - run(): Promise { - if (this.model.isHidden(this.id)) { - this.model.show(this.id); - } else { - this.model.hide(this.id); - } - - return Promise.resolve(true); - } -} - -class HideStatusbarEntryAction extends Action { - - constructor(id: string, private model: StatusbarViewModel) { - super(id, nls.localize('hide', "Hide"), undefined, true); - } - - run(): Promise { - this.model.hide(this.id); - - return Promise.resolve(true); - } -} +interface PendingEntry { entry: IStatusbarEntry; alignment: StatusbarAlignment; priority: number; accessor?: IStatusbarEntryAccessor; } export class StatusbarPart extends Part implements IStatusbarService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: ServiceIdentifier; + + private static readonly PRIORITY_PROP = 'statusbar-entry-priority'; + private static readonly ALIGNMENT_PROP = 'statusbar-entry-alignment'; //#region IView @@ -329,27 +49,20 @@ export class StatusbarPart extends Part implements IStatusbarService { //#endregion + private statusMessageDispose: IDisposable; private styleElement: HTMLStyleElement; - private pendingEntries: IPendingStatusbarEntry[] = []; - - private readonly viewModel: StatusbarViewModel; - - private leftItemsContainer: HTMLElement; - private rightItemsContainer: HTMLElement; + private pendingEntries: PendingEntry[] = []; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @IStorageService storageService: IStorageService, - @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, - @IContextMenuService private contextMenuService: IContextMenuService + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService ) { super(Parts.STATUSBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); - this.viewModel = this._register(new StatusbarViewModel(storageService)); - this.registerListeners(); } @@ -357,233 +70,133 @@ export class StatusbarPart extends Part implements IStatusbarService { this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); } - addEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor { + addEntry(entry: IStatusbarEntry, alignment: StatusbarAlignment, priority: number = 0): IStatusbarEntryAccessor { // As long as we have not been created into a container yet, record all entries // that are pending so that they can get created at a later point if (!this.element) { - return this.doAddPendingEntry(entry, id, name, alignment, priority); + const pendingEntry: PendingEntry = { + entry, alignment, priority + }; + this.pendingEntries.push(pendingEntry); + + const accessor: IStatusbarEntryAccessor = { + update: (entry: IStatusbarEntry) => { + if (pendingEntry.accessor) { + pendingEntry.accessor.update(entry); + } else { + pendingEntry.entry = entry; + } + }, + dispose: () => { + if (pendingEntry.accessor) { + pendingEntry.accessor.dispose(); + } else { + this.pendingEntries = this.pendingEntries.filter(entry => entry !== pendingEntry); + } + } + }; + return accessor; } - // Otherwise add to view - return this.doAddEntry(entry, id, name, alignment, priority); - } + // Render entry in status bar + const el = this.doCreateStatusItem(alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined])); + const item = this.instantiationService.createInstance(StatusBarEntryItem, el, entry); - private doAddPendingEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor { - const pendingEntry: IPendingStatusbarEntry = { entry, id, name, alignment, priority }; - this.pendingEntries.push(pendingEntry); - - const accessor: IStatusbarEntryAccessor = { - update: (entry: IStatusbarEntry) => { - if (pendingEntry.accessor) { - pendingEntry.accessor.update(entry); - } else { - pendingEntry.entry = entry; - } - }, - - dispose: () => { - if (pendingEntry.accessor) { - pendingEntry.accessor.dispose(); - } else { - this.pendingEntries = this.pendingEntries.filter(entry => entry !== pendingEntry); - } + // Insert according to priority + const container = this.element; + const neighbours = this.getEntries(alignment); + let inserted = false; + for (const neighbour of neighbours) { + const nPriority = Number(neighbour.getAttribute(StatusbarPart.PRIORITY_PROP)); + if ( + alignment === StatusbarAlignment.LEFT && nPriority < priority || + alignment === StatusbarAlignment.RIGHT && nPriority > priority + ) { + container.insertBefore(el, neighbour); + inserted = true; + break; } - }; + } - return accessor; - } - - private doAddEntry(entry: IStatusbarEntry, id: string, name: string, alignment: StatusbarAlignment, priority: number): IStatusbarEntryAccessor { - - // Create item - const itemContainer = this.doCreateStatusItem(id, name, alignment, priority, ...coalesce(['statusbar-entry', entry.showBeak ? 'has-beak' : undefined])); - const item = this.instantiationService.createInstance(StatusbarEntryItem, itemContainer, entry); - - // Append to parent - this.appendOneStatusbarEntry(itemContainer, alignment, priority); - - // Add to view model - const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer }; - const viewModelEntryDispose = this.viewModel.add(viewModelEntry); + if (!inserted) { + container.appendChild(el); + } return { update: entry => { // Update beak if (entry.showBeak) { - addClass(itemContainer, 'has-beak'); + addClass(el, 'has-beak'); } else { - removeClass(itemContainer, 'has-beak'); + removeClass(el, 'has-beak'); } // Update entry item.update(entry); }, dispose: () => { - dispose(viewModelEntryDispose); - itemContainer.remove(); + el.remove(); dispose(item); } }; } - updateEntryVisibility(id: string, visible: boolean): void { - if (visible) { - this.viewModel.show(id); - } else { - this.viewModel.hide(id); + private getEntries(alignment: StatusbarAlignment): HTMLElement[] { + const entries: HTMLElement[] = []; + + const container = this.element; + const children = container.children; + for (let i = 0; i < children.length; i++) { + const childElement = children.item(i); + if (Number(childElement.getAttribute(StatusbarPart.ALIGNMENT_PROP)) === alignment) { + entries.push(childElement); + } } + + return entries; } createContentArea(parent: HTMLElement): HTMLElement { this.element = parent; - // Left items container - this.leftItemsContainer = document.createElement('div'); - addClasses(this.leftItemsContainer, 'left-items', 'items-container'); - this.element.appendChild(this.leftItemsContainer); - - // Right items container - this.rightItemsContainer = document.createElement('div'); - addClasses(this.rightItemsContainer, 'right-items', 'items-container'); - this.element.appendChild(this.rightItemsContainer); - - // Context menu support - this._register(addDisposableListener(parent, EventType.CONTEXT_MENU, e => this.showContextMenu(e))); - - // Initial status bar entries - this.createInitialStatusbarEntries(); - - return this.element; - } - - private createInitialStatusbarEntries(): void { + // Fill in initial items that were contributed from the registry const registry = Registry.as(Extensions.Statusbar); - // Create initial items that were contributed from the registry - for (const { id, name, alignment, priority, syncDescriptor } of registry.items) { + const descriptors = registry.items.slice().sort((a, b) => { + if (a.alignment === b.alignment) { + if (a.alignment === StatusbarAlignment.LEFT) { + return b.priority - a.priority; + } else { + return a.priority - b.priority; + } + } else if (a.alignment === StatusbarAlignment.LEFT) { + return 1; + } else if (a.alignment === StatusbarAlignment.RIGHT) { + return -1; + } else { + return 0; + } + }); - // Create item - const item = this.instantiationService.createInstance(syncDescriptor); - const itemContainer = this.doCreateStatusItem(id, name, alignment, priority); - this._register(item.render(itemContainer)); + for (const descriptor of descriptors) { + const item = this.instantiationService.createInstance(descriptor.syncDescriptor); + const el = this.doCreateStatusItem(descriptor.alignment, descriptor.priority); - // Add to view model - const viewModelEntry: IStatusbarViewModelEntry = { id, name, alignment, priority, container: itemContainer }; - this.viewModel.add(viewModelEntry); + this._register(item.render(el)); + this.element.appendChild(el); } - // Add items in order according to alignment - this.appendAllStatusbarEntries(); - // Fill in pending entries if any while (this.pendingEntries.length) { - const pending = this.pendingEntries.shift(); - if (pending) { - pending.accessor = this.addEntry(pending.entry, pending.id, pending.name, pending.alignment, pending.priority); - } - } - } - - private appendAllStatusbarEntries(): void { - - // Append in order of priority - [ - ...this.viewModel.getEntries(StatusbarAlignment.LEFT), - ...this.viewModel.getEntries(StatusbarAlignment.RIGHT).reverse() // reversing due to flex: row-reverse - ].forEach(entry => { - const target = entry.alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer; - - target.appendChild(entry.container); - }); - } - - private appendOneStatusbarEntry(itemContainer: HTMLElement, alignment: StatusbarAlignment, priority: number): void { - const entries = this.viewModel.getEntries(alignment); - - if (alignment === StatusbarAlignment.RIGHT) { - entries.reverse(); // reversing due to flex: row-reverse - } - - const target = alignment === StatusbarAlignment.LEFT ? this.leftItemsContainer : this.rightItemsContainer; - - // find an entry that has lower priority than the new one - // and then insert the item before that one - let appended = false; - for (const entry of entries) { - if ( - alignment === StatusbarAlignment.LEFT && entry.priority < priority || - alignment === StatusbarAlignment.RIGHT && entry.priority > priority // reversing due to flex: row-reverse - ) { - target.insertBefore(itemContainer, entry.container); - appended = true; - break; - } - } - - // Fallback to just appending otherwise - if (!appended) { - target.appendChild(itemContainer); - } - } - - private showContextMenu(e: MouseEvent): void { - EventHelper.stop(e, true); - - const event = new StandardMouseEvent(e); - - let actions: IAction[] | undefined = undefined; - this.contextMenuService.showContextMenu({ - getAnchor: () => ({ x: event.posx, y: event.posy }), - getActions: () => { - actions = this.getContextMenuActions(event); - - return actions; - }, - onHide: () => { - if (actions) { - dispose(actions); - } - } - }); - } - - private getContextMenuActions(event: StandardMouseEvent): IAction[] { - const actions: Action[] = []; - - // Figure out if mouse is over an entry - let statusEntryUnderMouse: IStatusbarViewModelEntry | undefined = undefined; - for (let element: HTMLElement | null = event.target; element; element = element.parentElement) { - const entry = this.viewModel.findEntry(element); + const entry = this.pendingEntries.shift(); if (entry) { - statusEntryUnderMouse = entry; - break; + entry.accessor = this.addEntry(entry.entry, entry.alignment, entry.priority); } } - if (statusEntryUnderMouse) { - actions.push(new HideStatusbarEntryAction(statusEntryUnderMouse.id, this.viewModel)); - actions.push(new Separator()); - } - - // Show an entry per known status entry - // Note: even though entries have an identifier, there can be multiple entries - // having the same identifier (e.g. from extensions). So we make sure to only - // show a single entry per identifier we handled. - const handledEntries = new Set(); - this.viewModel.entries.forEach(entry => { - if (!handledEntries.has(entry.id)) { - actions.push(new ToggleStatusbarEntryVisibilityAction(entry.id, entry.name, this.viewModel)); - handledEntries.add(entry.id); - } - }); - - // Provide an action to hide the status bar at last - actions.push(new Separator()); - actions.push(this.instantiationService.createInstance(ToggleStatusbarVisibilityAction, ToggleStatusbarVisibilityAction.ID, nls.localize('hideStatusBar', "Hide Status Bar"))); - - return actions; + return this.element; } updateStyles(): void { @@ -607,25 +220,64 @@ export class StatusbarPart extends Part implements IStatusbarService { this.styleElement = createStyleSheet(container); } - this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`; + this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor}; }`; } - private doCreateStatusItem(id: string, name: string, alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement { - const itemContainer = document.createElement('div'); - itemContainer.title = name; - - addClass(itemContainer, 'statusbar-item'); + private doCreateStatusItem(alignment: StatusbarAlignment, priority: number = 0, ...extraClasses: string[]): HTMLElement { + const el = document.createElement('div'); + addClass(el, 'statusbar-item'); if (extraClasses) { - addClasses(itemContainer, ...extraClasses); + addClasses(el, ...extraClasses); } if (alignment === StatusbarAlignment.RIGHT) { - addClass(itemContainer, 'right'); + addClass(el, 'right'); } else { - addClass(itemContainer, 'left'); + addClass(el, 'left'); } - return itemContainer; + el.setAttribute(StatusbarPart.PRIORITY_PROP, String(priority)); + el.setAttribute(StatusbarPart.ALIGNMENT_PROP, String(alignment)); + + return el; + } + + setStatusMessage(message: string, autoDisposeAfter: number = -1, delayBy: number = 0): IDisposable { + + // Dismiss any previous + dispose(this.statusMessageDispose); + + // Create new + let statusMessageEntry: IStatusbarEntryAccessor; + let showHandle: any = setTimeout(() => { + statusMessageEntry = this.addEntry({ text: message }, StatusbarAlignment.LEFT, -Number.MAX_VALUE /* far right on left hand side */); + showHandle = null; + }, delayBy); + let hideHandle: any; + + // Dispose function takes care of timeouts and actual entry + const statusMessageDispose = { + dispose: () => { + if (showHandle) { + clearTimeout(showHandle); + } + + if (hideHandle) { + clearTimeout(hideHandle); + } + + if (statusMessageEntry) { + statusMessageEntry.dispose(); + } + } + }; + this.statusMessageDispose = statusMessageDispose; + + if (typeof autoDisposeAfter === 'number' && autoDisposeAfter > 0) { + hideHandle = setTimeout(() => statusMessageDispose.dispose(), autoDisposeAfter); + } + + return statusMessageDispose; } layout(width: number, height: number): void { @@ -639,20 +291,27 @@ export class StatusbarPart extends Part implements IStatusbarService { } } -class StatusbarEntryItem extends Disposable { +let manageExtensionAction: ManageExtensionAction; +class StatusBarEntryItem extends Disposable { private entryDisposables: IDisposable[] = []; constructor( private container: HTMLElement, entry: IStatusbarEntry, @ICommandService private readonly commandService: ICommandService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, @IEditorService private readonly editorService: IEditorService, @IThemeService private readonly themeService: IThemeService ) { super(); + if (!manageExtensionAction) { + manageExtensionAction = this.instantiationService.createInstance(ManageExtensionAction); + } + this.render(entry); } @@ -692,6 +351,19 @@ class StatusbarEntryItem extends Disposable { addClass(this.container, 'has-background-color'); } + // Context Menu + if (entry.extensionId) { + this.entryDisposables.push((addDisposableListener(textContainer, 'contextmenu', e => { + EventHelper.stop(e, true); + + this.contextMenuService.showContextMenu({ + getAnchor: () => this.container, + getActionsContext: () => entry.extensionId!.value, + getActions: () => [manageExtensionAction] + }); + }))); + } + this.container.appendChild(textContainer); } @@ -740,30 +412,43 @@ class StatusbarEntryItem extends Disposable { } } +class ManageExtensionAction extends Action { + + constructor( + @ICommandService private readonly commandService: ICommandService + ) { + super('statusbar.manage.extension', nls.localize('manageExtension', "Manage Extension")); + } + + run(extensionId: string): Promise { + return this.commandService.executeCommand('_extensions.manage', extensionId); + } +} + registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND); if (statusBarItemHoverBackground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item a:hover { background-color: ${statusBarItemHoverBackground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a:hover { background-color: ${statusBarItemHoverBackground}; }`); } const statusBarItemActiveBackground = theme.getColor(STATUS_BAR_ITEM_ACTIVE_BACKGROUND); if (statusBarItemActiveBackground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item a:active { background-color: ${statusBarItemActiveBackground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a:active { background-color: ${statusBarItemActiveBackground}; }`); } const statusBarProminentItemForeground = theme.getColor(STATUS_BAR_PROMINENT_ITEM_FOREGROUND); if (statusBarProminentItemForeground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item .status-bar-info { color: ${statusBarProminentItemForeground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item .status-bar-info { color: ${statusBarProminentItemForeground}; }`); } const statusBarProminentItemBackground = theme.getColor(STATUS_BAR_PROMINENT_ITEM_BACKGROUND); if (statusBarProminentItemBackground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item .status-bar-info { background-color: ${statusBarProminentItemBackground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item .status-bar-info { background-color: ${statusBarProminentItemBackground}; }`); } const statusBarProminentItemHoverBackground = theme.getColor(STATUS_BAR_PROMINENT_ITEM_HOVER_BACKGROUND); if (statusBarProminentItemHoverBackground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item a.status-bar-info:hover { background-color: ${statusBarProminentItemHoverBackground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item a.status-bar-info:hover { background-color: ${statusBarProminentItemHoverBackground}; }`); } }); diff --git a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css index 0763038112..7413f2e16f 100644 --- a/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css +++ b/src/vs/workbench/browser/parts/titlebar/media/titlebarpart.css @@ -41,7 +41,7 @@ } /* Windows/Linux: Rules for custom title (icon, window controls) */ -.monaco-workbench.web .part.titlebar, + .monaco-workbench.windows .part.titlebar, .monaco-workbench.linux .part.titlebar { padding: 0; @@ -51,7 +51,6 @@ overflow: visible; } -.monaco-workbench.web .part.titlebar > .window-title, .monaco-workbench.windows .part.titlebar > .window-title, .monaco-workbench.linux .part.titlebar > .window-title { cursor: default; diff --git a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts index 8a9cf5070d..62ebb0ac85 100644 --- a/src/vs/workbench/browser/parts/titlebar/menubarControl.ts +++ b/src/vs/workbench/browser/parts/titlebar/menubarControl.ts @@ -13,7 +13,7 @@ import { IAction, Action } from 'vs/base/common/actions'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import * as DOM from 'vs/base/browser/dom'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { isMacintosh, isWeb } from 'vs/base/common/platform'; +import { isMacintosh, isLinux } from 'vs/base/common/platform'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { Event, Emitter } from 'vs/base/common/event'; import { Disposable } from 'vs/base/common/lifecycle'; @@ -34,19 +34,22 @@ import { assign } from 'vs/base/common/objects'; import { mnemonicMenuLabel, unmnemonicLabel } from 'vs/base/common/labels'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { withNullAsUndefined } from 'vs/base/common/types'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ServicesAccessor } from 'vs/editor/browser/editorExtensions'; export class MenubarControl extends Disposable { private keys = [ + 'files.autoSave', 'window.menuBarVisibility', + 'editor.multiCursorModifier', + 'workbench.sideBar.location', + 'workbench.statusBar.visible', + 'workbench.activityBar.visible', 'window.enableMenuBarMnemonics', 'window.nativeTabs' ]; // {{SQL CARBON EDIT}} - Disable unusued menus - private menus: { + private topLevelMenus: { 'File': IMenu; 'Edit': IMenu; // 'Selection': IMenu; @@ -76,17 +79,15 @@ export class MenubarControl extends Disposable { private container: HTMLElement; private recentlyOpened: IRecentlyOpened; private alwaysOnMnemonics: boolean; - private isNative: boolean; private readonly _onVisibilityChange: Emitter; private readonly _onFocusStateChange: Emitter; - private menubarService: IMenubarService; - private static MAX_MENU_RECENT_ENTRIES = 10; constructor( @IThemeService private readonly themeService: IThemeService, + @IMenubarService private readonly menubarService: IMenubarService, @IMenuService private readonly menuService: IMenuService, @IWindowService private readonly windowService: IWindowService, @IWindowsService private readonly windowsService: IWindowsService, @@ -99,22 +100,13 @@ export class MenubarControl extends Disposable { @INotificationService private readonly notificationService: INotificationService, @IPreferencesService private readonly preferencesService: IPreferencesService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IAccessibilityService private readonly accessibilityService: IAccessibilityService, - @IInstantiationService private readonly instantiationService: IInstantiationService + @IAccessibilityService private readonly accessibilityService: IAccessibilityService ) { super(); - this.isNative = !isWeb && (isMacintosh || this.currentTitlebarStyleSetting !== 'custom'); - - this.instantiationService.invokeFunction((accessor: ServicesAccessor) => { - if (this.isNative) { - this.menubarService = accessor.get(IMenubarService); - } - }); - - // {{SQL CARBON EDIT}} - Disable unusued menus - this.menus = { + // {{SQL CARBON EDIT}} - Disable unused menus + this.topLevelMenus = { 'File': this._register(this.menuService.createMenu(MenuId.MenubarFileMenu, this.contextKeyService)), 'Edit': this._register(this.menuService.createMenu(MenuId.MenubarEditMenu, this.contextKeyService)), // 'Selection': this._register(this.menuService.createMenu(MenuId.MenubarSelectionMenu, this.contextKeyService)), @@ -125,9 +117,8 @@ export class MenubarControl extends Disposable { 'Help': this._register(this.menuService.createMenu(MenuId.MenubarHelpMenu, this.contextKeyService)) }; - if (isMacintosh && this.isNative) { - this.menus['Preferences'] = this._register(this.menuService.createMenu(MenuId.MenubarPreferencesMenu, this.contextKeyService)); - this.topLevelTitles['Preferences'] = nls.localize('mPreferences', "Preferences"); + if (isMacintosh) { + this.topLevelMenus['Preferences'] = this._register(this.menuService.createMenu(MenuId.MenubarPreferencesMenu, this.contextKeyService)); } this.menuUpdater = this._register(new RunOnceScheduler(() => this.doUpdateMenubar(false), 200)); @@ -135,9 +126,9 @@ export class MenubarControl extends Disposable { this._onVisibilityChange = this._register(new Emitter()); this._onFocusStateChange = this._register(new Emitter()); - if (this.isNative) { - for (const topLevelMenuName of Object.keys(this.topLevelTitles)) { - const menu = this.menus[topLevelMenuName]; + if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') { + for (const topLevelMenuName of Object.keys(this.topLevelMenus)) { + const menu = this.topLevelMenus[topLevelMenuName]; if (menu) { this._register(menu.onDidChange(() => this.updateMenubar())); } @@ -147,11 +138,13 @@ export class MenubarControl extends Disposable { this.windowService.getRecentlyOpened().then((recentlyOpened) => { this.recentlyOpened = recentlyOpened; - if (this.isNative) { + if (isMacintosh || this.currentTitlebarStyleSetting !== 'custom') { this.doUpdateMenubar(true); } }); + this.notifyExistingLinuxUser(); + this.notifyUserOfCustomMenubarAccessibility(); this.registerListeners(); @@ -166,6 +159,28 @@ export class MenubarControl extends Disposable { return enableMenuBarMnemonics; } + private get currentSidebarPosition(): string { + return this.configurationService.getValue('workbench.sideBar.location'); + } + + private get currentStatusBarVisibility(): boolean { + let setting = this.configurationService.getValue('workbench.statusBar.visible'); + if (typeof setting !== 'boolean') { + setting = true; + } + + return setting; + } + + private get currentActivityBarVisibility(): boolean { + let setting = this.configurationService.getValue('workbench.activityBar.visible'); + if (typeof setting !== 'boolean') { + setting = true; + } + + return setting; + } + private get currentMenubarVisibility(): MenuBarVisibility { return this.configurationService.getValue('window.menuBarVisibility'); } @@ -202,8 +217,38 @@ export class MenubarControl extends Disposable { }); } + // TODO@sbatten remove after feb19 + private notifyExistingLinuxUser(): void { + if (!isLinux) { + return; + } + + const isNewUser = !this.storageService.get('telemetry.lastSessionDate', StorageScope.GLOBAL); + const hasBeenNotified = this.storageService.getBoolean('menubar/linuxTitlebarRevertNotified', StorageScope.GLOBAL, false); + const titleBarConfiguration = this.configurationService.inspect('window.titleBarStyle'); + const customShown = getTitleBarStyle(this.configurationService, this.environmentService) === 'custom'; + + if (!hasBeenNotified) { + this.storageService.store('menubar/linuxTitlebarRevertNotified', true, StorageScope.GLOBAL); + } + + if (isNewUser || hasBeenNotified || (titleBarConfiguration && titleBarConfiguration.user) || customShown) { + return; + } + + const message = nls.localize('menubar.linuxTitlebarRevertNotification', "We have updated the default title bar on Linux to use the native setting. If you prefer, you can go back to the custom setting. More information is available in our [online documentation](https://go.microsoft.com/fwlink/?linkid=2074137)."); + this.notificationService.prompt(Severity.Info, message, [ + { + label: nls.localize('goToSetting', "Open Settings"), + run: () => { + return this.preferencesService.openGlobalSettings(undefined, { query: 'window.titleBarStyle' }); + } + } + ]); + } + private notifyUserOfCustomMenubarAccessibility(): void { - if (isWeb || isMacintosh) { + if (isMacintosh) { return; } @@ -243,7 +288,7 @@ export class MenubarControl extends Disposable { this._register(this.keybindingService.onDidUpdateKeybindings(() => this.updateMenubar())); // These listeners only apply when the custom menubar is being used - if (!this.isNative) { + if (!isMacintosh && this.currentTitlebarStyleSetting === 'custom') { // Listen for window focus changes this._register(this.windowService.onDidChangeFocus(e => this.onDidChangeWindowFocus(e))); @@ -259,7 +304,7 @@ export class MenubarControl extends Disposable { } private doUpdateMenubar(firstTime: boolean): void { - if (!this.isNative) { + if (!isMacintosh && this.currentTitlebarStyleSetting === 'custom') { this.setupCustomMenubar(firstTime); } else { // Send menus to main process to be rendered by Electron @@ -277,6 +322,30 @@ export class MenubarControl extends Disposable { private calculateActionLabel(action: IAction | IMenubarMenuItemAction): string { let label = action.label; switch (action.id) { + case 'workbench.action.toggleSidebarPosition': + if (this.currentSidebarPosition !== 'right') { + label = nls.localize({ key: 'miMoveSidebarRight', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Right"); + } else { + label = nls.localize({ key: 'miMoveSidebarLeft', comment: ['&& denotes a mnemonic'] }, "&&Move Side Bar Left"); + } + break; + + case 'workbench.action.toggleStatusbarVisibility': + if (this.currentStatusBarVisibility) { + label = nls.localize({ key: 'miHideStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Hide Status Bar"); + } else { + label = nls.localize({ key: 'miShowStatusbar', comment: ['&& denotes a mnemonic'] }, "&&Show Status Bar"); + } + break; + + case 'workbench.action.toggleActivityBarVisibility': + if (this.currentActivityBarVisibility) { + label = nls.localize({ key: 'miHideActivityBar', comment: ['&& denotes a mnemonic'] }, "Hide &&Activity Bar"); + } else { + label = nls.localize({ key: 'miShowActivityBar', comment: ['&& denotes a mnemonic'] }, "Show &&Activity Bar"); + } + break; + default: break; } @@ -403,7 +472,7 @@ export class MenubarControl extends Disposable { break; case 'workbench.action.showAboutDialog': - if (!isMacintosh && !isWeb) { + if (!isMacintosh) { const updateAction = this.getUpdateAction(); if (updateAction) { updateAction.label = mnemonicMenuLabel(updateAction.label); @@ -443,7 +512,7 @@ export class MenubarControl extends Disposable { } // Update the menu actions - const updateActions = (menu: IMenu, target: IAction[], topLevelTitle: string) => { + const updateActions = (menu: IMenu, target: IAction[]) => { target.splice(0); let groups = menu.getActions(); for (let group of groups) { @@ -452,20 +521,11 @@ export class MenubarControl extends Disposable { for (let action of actions) { this.insertActionsBefore(action, target); if (action instanceof SubmenuItemAction) { - if (!this.menus[action.item.submenu]) { - this.menus[action.item.submenu] = this.menuService.createMenu(action.item.submenu, this.contextKeyService); - const submenu = this.menus[action.item.submenu]; - this._register(submenu!.onDidChange(() => { - const actions: IAction[] = []; - updateActions(menu, actions, topLevelTitle); - this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[topLevelTitle]) }); - }, this)); - } - - const submenu = this.menus[action.item.submenu]!; + const submenu = this.menuService.createMenu(action.item.submenu, this.contextKeyService); const submenuActions: SubmenuAction[] = []; - updateActions(submenu, submenuActions, topLevelTitle); + updateActions(submenu, submenuActions); target.push(new SubmenuAction(mnemonicMenuLabel(action.label), submenuActions)); + submenu.dispose(); } else { action.label = mnemonicMenuLabel(this.calculateActionLabel(action)); target.push(action); @@ -478,19 +538,19 @@ export class MenubarControl extends Disposable { target.pop(); }; - for (const title of Object.keys(this.topLevelTitles)) { - const menu = this.menus[title]; + for (const title of Object.keys(this.topLevelMenus)) { + const menu = this.topLevelMenus[title]; if (firstTime && menu) { this._register(menu.onDidChange(() => { const actions: IAction[] = []; - updateActions(menu, actions, title); + updateActions(menu, actions); this.menubar.updateMenu({ actions: actions, label: mnemonicMenuLabel(this.topLevelTitles[title]) }); })); } const actions: IAction[] = []; if (menu) { - updateActions(menu, actions, title); + updateActions(menu, actions); } if (!firstTime) { @@ -531,12 +591,6 @@ export class MenubarControl extends Disposable { if (menuItem instanceof SubmenuItemAction) { const submenu = { items: [] }; - - if (!this.menus[menuItem.item.submenu]) { - this.menus[menuItem.item.submenu] = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService); - this._register(this.menus[menuItem.item.submenu]!.onDidChange(() => this.updateMenubar())); - } - const menuToDispose = this.menuService.createMenu(menuItem.item.submenu, this.contextKeyService); this.populateMenuItems(menuToDispose, submenu, keybindings); @@ -583,7 +637,7 @@ export class MenubarControl extends Disposable { private getAdditionalKeybindings(): { [id: string]: IMenubarKeybinding } { const keybindings = {}; - if (isMacintosh && this.isNative) { + if (isMacintosh) { keybindings['workbench.action.quit'] = (this.getMenubarKeybinding('workbench.action.quit')); } @@ -596,8 +650,8 @@ export class MenubarControl extends Disposable { } menubarData.keybindings = this.getAdditionalKeybindings(); - for (const topLevelMenuName of Object.keys(this.topLevelTitles)) { - const menu = this.menus[topLevelMenuName]; + for (const topLevelMenuName of Object.keys(this.topLevelMenus)) { + const menu = this.topLevelMenus[topLevelMenuName]; if (menu) { const menubarMenu: IMenubarMenu = { items: [] }; this.populateMenuItems(menu, menubarMenu, menubarData.keybindings); @@ -644,7 +698,7 @@ export class MenubarControl extends Disposable { // Build the menubar if (this.container) { - if (!this.isNative) { + if (!isMacintosh && this.currentTitlebarStyleSetting === 'custom') { this.doUpdateMenubar(true); } } diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index b22fcdfc6f..388d3279ba 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -22,7 +22,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; import { TITLE_BAR_ACTIVE_BACKGROUND, TITLE_BAR_ACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_FOREGROUND, TITLE_BAR_INACTIVE_BACKGROUND, TITLE_BAR_BORDER } from 'vs/workbench/common/theme'; -import { isMacintosh, isWindows, isLinux, isWeb } from 'vs/base/common/platform'; +import { isMacintosh, isWindows, isLinux } from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; import { Color } from 'vs/base/common/color'; import { trim } from 'vs/base/common/strings'; @@ -50,8 +50,8 @@ export class TitlebarPart extends Part implements ITitleService { readonly minimumWidth: number = 0; readonly maximumWidth: number = Number.POSITIVE_INFINITY; - get minimumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } - get maximumHeight(): number { return isMacintosh && !isWeb ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } + get minimumHeight(): number { return isMacintosh ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } + get maximumHeight(): number { return isMacintosh ? 22 / getZoomFactor() : (30 / (this.configurationService.getValue('window.menuBarVisibility') === 'hidden' ? getZoomFactor() : 1)); } //#endregion @@ -135,9 +135,9 @@ export class TitlebarPart extends Part implements ITitleService { } private onMenubarVisibilityChanged(visible: boolean) { - if (isWeb || isWindows || isLinux) { + if (isWindows || isLinux) { // Hide title when toggling menu bar - if (!isWeb && this.configurationService.getValue('window.menuBarVisibility') === 'toggle' && visible) { + if (this.configurationService.getValue('window.menuBarVisibility') === 'toggle' && visible) { // Hack to fix issue #52522 with layered webkit-app-region elements appearing under cursor hide(this.dragRegion); setTimeout(() => show(this.dragRegion), 50); @@ -150,7 +150,7 @@ export class TitlebarPart extends Part implements ITitleService { } private onMenubarFocusChanged(focused: boolean) { - if (!isWeb && (isWindows || isLinux)) { + if (isWindows || isLinux) { if (focused) { hide(this.dragRegion); } else { @@ -207,7 +207,7 @@ export class TitlebarPart extends Part implements ITitleService { this.pendingTitle = title; } - if ((isWeb || isWindows || isLinux) && this.title) { + if ((isWindows || isLinux) && this.title) { if (this.lastLayoutDimensions) { this.updateLayout(this.lastLayoutDimensions); } @@ -322,12 +322,10 @@ export class TitlebarPart extends Part implements ITitleService { this.element = parent; // Draggable region that we can manipulate for #52522 - if (!isWeb) { - this.dragRegion = append(this.element, $('div.titlebar-drag-region')); - } + this.dragRegion = append(this.element, $('div.titlebar-drag-region')); - // App Icon (Native Windows/Linux) - if (!isMacintosh && !isWeb) { + // App Icon (Windows/Linux) + if (!isMacintosh) { this.appIcon = append(this.element, $('div.window-appicon')); this.onUpdateAppIconDragBehavior(); @@ -343,7 +341,7 @@ export class TitlebarPart extends Part implements ITitleService { this.menubarPart.create(this.menubar); - if (!isMacintosh || isWeb) { + if (!isMacintosh) { this._register(this.menubarPart.onVisibilityChange(e => this.onMenubarVisibilityChanged(e))); this._register(this.menubarPart.onFocusStateChange(e => this.onMenubarFocusChanged(e))); } @@ -357,7 +355,7 @@ export class TitlebarPart extends Part implements ITitleService { } // Maximize/Restore on doubleclick - if (isMacintosh && !isWeb) { + if (isMacintosh) { this._register(addDisposableListener(this.element, EventType.DBLCLICK, e => { EventHelper.stop(e); @@ -376,8 +374,8 @@ export class TitlebarPart extends Part implements ITitleService { })); }); - // Window Controls (Native Windows/Linux) - if (!isMacintosh && !isWeb) { + // Window Controls (Windows/Linux) + if (!isMacintosh) { this.windowControls = append(this.element, $('div.window-controls-container')); @@ -548,24 +546,17 @@ export class TitlebarPart extends Part implements ITitleService { } private adjustTitleMarginToCenter(): void { - if (!isMacintosh || isWeb) { - const leftMarker = (this.appIcon ? this.appIcon.clientWidth : 0) + this.menubar.clientWidth + 10; - const rightMarker = this.element.clientWidth - (this.windowControls ? this.windowControls.clientWidth : 0) - 10; - - // Not enough space to center the titlebar within window, - // Center between menu and window controls - if (leftMarker > (this.element.clientWidth - this.title.clientWidth) / 2 || - rightMarker < (this.element.clientWidth + this.title.clientWidth) / 2) { - this.title.style.position = null; - this.title.style.left = null; - this.title.style.transform = null; - return; - } + if (!isMacintosh && + (this.appIcon.clientWidth + this.menubar.clientWidth + 10 > (this.element.clientWidth - this.title.clientWidth) / 2 || + this.element.clientWidth - this.windowControls.clientWidth - 10 < (this.element.clientWidth + this.title.clientWidth) / 2)) { + this.title.style.position = null; + this.title.style.left = null; + this.title.style.transform = null; + } else { + this.title.style.position = 'absolute'; + this.title.style.left = '50%'; + this.title.style.transform = 'translate(-50%, 0)'; } - - this.title.style.position = 'absolute'; - this.title.style.left = '50%'; - this.title.style.transform = 'translate(-50%, 0)'; } updateLayout(dimension: Dimension): void { @@ -573,15 +564,15 @@ export class TitlebarPart extends Part implements ITitleService { if (getTitleBarStyle(this.configurationService, this.environmentService) === 'custom') { // Only prevent zooming behavior on macOS or when the menubar is not visible - if ((!isWeb && isMacintosh) || this.configurationService.getValue('window.menuBarVisibility') === 'hidden') { + if (isMacintosh || this.configurationService.getValue('window.menuBarVisibility') === 'hidden') { this.title.style.zoom = `${1 / getZoomFactor()}`; - if (!isWeb && (isWindows || isLinux)) { + if (isWindows || isLinux) { this.appIcon.style.zoom = `${1 / getZoomFactor()}`; this.windowControls.style.zoom = `${1 / getZoomFactor()}`; } } else { this.title.style.zoom = null; - if (!isWeb && (isWindows || isLinux)) { + if (isWindows || isLinux) { this.appIcon.style.zoom = null; this.windowControls.style.zoom = null; } diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index 6d3e69f4bf..0d23af2842 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -17,7 +17,7 @@ import { IViewsService, ITreeView, ITreeItem, TreeItemCollapsibleState, ITreeVie import { IViewletViewOptions, FileIconThemableWorkbenchTree } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService2 } from 'vs/platform/progress/common/progress'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -60,9 +60,9 @@ export class CustomTreeViewPanel extends ViewletPanel { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); const { treeView } = (Registry.as(Extensions.ViewsRegistry).getView(options.id)); this.treeView = treeView; - this._register(this.treeView.onDidChangeActions(() => this.updateActions(), this)); - this._register(toDisposable(() => this.treeView.setVisibility(false))); - this._register(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility())); + this.treeView.onDidChangeActions(() => this.updateActions(), this, this.disposables); + this.disposables.push(toDisposable(() => this.treeView.setVisibility(false))); + this.disposables.push(this.onDidChangeBodyVisibility(() => this.updateTreeVisibility())); this.updateTreeVisibility(); } @@ -98,6 +98,11 @@ export class CustomTreeViewPanel extends ViewletPanel { private updateTreeVisibility(): void { this.treeView.setVisibility(this.isBodyVisible()); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } class TitleMenus implements IDisposable { @@ -211,7 +216,7 @@ export class CustomTreeView extends Disposable implements ITreeView { @IInstantiationService private readonly instantiationService: IInstantiationService, @ICommandService private readonly commandService: ICommandService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IProgressService private readonly progressService: IProgressService + @IProgressService2 private readonly progressService: IProgressService2 ) { super(); this.root = new Root(); diff --git a/src/vs/workbench/browser/parts/views/panelViewlet.ts b/src/vs/workbench/browser/parts/views/panelViewlet.ts index a1d047083b..b6bdf29506 100644 --- a/src/vs/workbench/browser/parts/views/panelViewlet.ts +++ b/src/vs/workbench/browser/parts/views/panelViewlet.ts @@ -46,16 +46,16 @@ export abstract class ViewletPanel extends Panel implements IView { private static AlwaysShowActionsConfig = 'workbench.view.alwaysShowHeaderActions'; - private _onDidFocus = this._register(new Emitter()); + private _onDidFocus = new Emitter(); readonly onDidFocus: Event = this._onDidFocus.event; - private _onDidBlur = this._register(new Emitter()); + private _onDidBlur = new Emitter(); readonly onDidBlur: Event = this._onDidBlur.event; - private _onDidChangeBodyVisibility = this._register(new Emitter()); + private _onDidChangeBodyVisibility = new Emitter(); readonly onDidChangeBodyVisibility: Event = this._onDidChangeBodyVisibility.event; - protected _onDidChangeTitleArea = this._register(new Emitter()); + protected _onDidChangeTitleArea = new Emitter(); readonly onDidChangeTitleArea: Event = this._onDidChangeTitleArea.event; private _isVisible: boolean = false; @@ -78,6 +78,8 @@ export abstract class ViewletPanel extends Panel implements IView { this.id = options.id; this.title = options.title; this.actionRunner = options.actionRunner; + + this.disposables.push(this._onDidFocus, this._onDidBlur, this._onDidChangeBodyVisibility, this._onDidChangeTitleArea); } setVisible(visible: boolean): void { @@ -111,9 +113,9 @@ export abstract class ViewletPanel extends Panel implements IView { super.render(); const focusTracker = trackFocus(this.element); - this._register(focusTracker); - this._register(focusTracker.onDidFocus(() => this._onDidFocus.fire())); - this._register(focusTracker.onDidBlur(() => this._onDidBlur.fire())); + this.disposables.push(focusTracker); + this.disposables.push(focusTracker.onDidFocus(() => this._onDidFocus.fire())); + this.disposables.push(focusTracker.onDidBlur(() => this._onDidBlur.fire())); } protected renderHeader(container: HTMLElement): void { @@ -130,11 +132,11 @@ export abstract class ViewletPanel extends Panel implements IView { actionRunner: this.actionRunner }); - this._register(this.toolbar); + this.disposables.push(this.toolbar); this.setActions(); const onDidRelevantConfigurationChange = Event.filter(this.configurationService.onDidChangeConfiguration, e => e.affectsConfiguration(ViewletPanel.AlwaysShowActionsConfig)); - this._register(onDidRelevantConfigurationChange(this.updateActionsVisibility, this)); + onDidRelevantConfigurationChange(this.updateActionsVisibility, this, this.disposables); this.updateActionsVisibility(); } @@ -353,7 +355,7 @@ export class PanelViewlet extends Viewlet { headerBorder: SIDE_BAR_SECTION_HEADER_BORDER, dropBackground: SIDE_BAR_DRAG_AND_DROP_BACKGROUND }, panel); - const disposable = combinedDisposable(onDidFocus, onDidChangeTitleArea, panelStyler, onDidChange); + const disposable = combinedDisposable([onDidFocus, onDidChangeTitleArea, panelStyler, onDidChange]); const panelItem: IViewletPanelItem = { panel, disposable }; this.panelItems.splice(index, 0, panelItem); diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 5f877fd885..7053b2f079 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -29,15 +29,14 @@ import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/la import { localize } from 'vs/nls'; import { IAddedViewDescriptorRef, IViewDescriptorRef, PersistentContributableViewsModel } from 'vs/workbench/browser/parts/views/views'; import { Registry } from 'vs/platform/registry/common/platform'; -import { MementoObject } from 'vs/workbench/common/memento'; export interface IViewletViewOptions extends IViewletPanelOptions { - viewletState: MementoObject; + viewletState: object; } export abstract class ViewContainerViewlet extends PanelViewlet implements IViewsViewlet { - private readonly viewletState: MementoObject; + private readonly viewletState: object; private didLayout = false; private dimension: DOM.Dimension; private areExtensionsReady: boolean = false; @@ -208,7 +207,7 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView this.viewsModel.setCollapsed(viewDescriptor.id, collapsed); }); - this.viewDisposables.splice(index, 0, combinedDisposable(contextMenuDisposable, collapseDisposable)); + this.viewDisposables.splice(index, 0, combinedDisposable([contextMenuDisposable, collapseDisposable])); panelsToAdd.push({ panel, size: size || panel.minimumSize, index }); } diff --git a/src/vs/workbench/browser/style.ts b/src/vs/workbench/browser/style.ts index 535c4d2432..96d47cf334 100644 --- a/src/vs/workbench/browser/style.ts +++ b/src/vs/workbench/browser/style.ts @@ -4,7 +4,6 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/style'; -import 'vs/css!./media/icons'; import { registerThemingParticipant, ITheme, ICssStyleCollector, HIGH_CONTRAST } from 'vs/platform/theme/common/themeService'; import { foreground, selectionBackground, focusBorder, scrollbarShadow, scrollbarSliderActiveBackground, scrollbarSliderBackground, scrollbarSliderHoverBackground, listHighlightForeground, inputPlaceholderForeground } from 'vs/platform/theme/common/colorRegistry'; diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 486568bcf8..76280b37f0 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -21,33 +21,13 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA import { IFileService } from 'vs/platform/files/common/files'; import { FileService } from 'vs/workbench/services/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { URI } from 'vs/base/common/uri'; -import { IWorkspaceInitializationPayload } from 'vs/platform/workspaces/common/workspaces'; -import { WorkspaceService } from 'vs/workbench/services/configuration/browser/configurationService'; -import { ConfigurationCache } from 'vs/workbench/services/configuration/browser/configurationCache'; -import { ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; -import { WebResources } from 'vs/workbench/browser/web.resources'; - -interface IWindowConfiguration { - settingsUri: URI; - remoteAuthority: string; - folderUri?: URI; - workspaceUri?: URI; -} class CodeRendererMain extends Disposable { private workbench: Workbench; - constructor(private readonly configuration: IWindowConfiguration) { - super(); - } - async open(): Promise { - const services = await this.initServices(); + const services = this.initServices(); await domContentLoaded(); mark('willStartWorkbench'); @@ -62,9 +42,6 @@ class CodeRendererMain extends Disposable { // Layout this._register(addDisposableListener(window, EventType.RESIZE, () => this.workbench.layout())); - // Resource Loading - this._register(new WebResources(services.serviceCollection.get(IFileService))); - // Workbench Lifecycle this._register(this.workbench.onShutdown(() => this.dispose())); @@ -72,7 +49,7 @@ class CodeRendererMain extends Disposable { this.workbench.startup(); } - private async initServices(): Promise<{ serviceCollection: ServiceCollection, logService: ILogService }> { + private initServices(): { serviceCollection: ServiceCollection, logService: ILogService } { const serviceCollection = new ServiceCollection(); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! @@ -85,7 +62,7 @@ class CodeRendererMain extends Disposable { serviceCollection.set(ILogService, logService); // Environment - const environmentService = this.createEnvironmentService(); + const environmentService = new SimpleWorkbenchEnvironmentService(); serviceCollection.set(IWorkbenchEnvironmentService, environmentService); // Product @@ -110,101 +87,12 @@ class CodeRendererMain extends Disposable { fileService.registerProvider(Schemas.vscodeRemote, remoteFileSystemProvider); } - const payload = await this.resolveWorkspaceInitializationPayload(); - - await Promise.all([ - this.createWorkspaceService(payload, fileService, remoteAgentService, logService).then(service => { - - // Workspace - serviceCollection.set(IWorkspaceContextService, service); - - // Configuration - serviceCollection.set(IConfigurationService, service); - - return service; - }), - ]); - return { serviceCollection, logService }; } - - private createEnvironmentService(): IWorkbenchEnvironmentService { - const environmentService = new SimpleWorkbenchEnvironmentService(); - environmentService.appRoot = '/web/'; - environmentService.args = { _: [] }; - environmentService.appSettingsHome = '/web/settings'; - environmentService.settingsResource = this.configuration.settingsUri; - environmentService.appKeybindingsPath = '/web/settings/keybindings.json'; - environmentService.logsPath = '/web/logs'; - environmentService.debugExtensionHost = { - port: null, - break: false - }; - return environmentService; - } - - private async createWorkspaceService(payload: IWorkspaceInitializationPayload, fileService: FileService, remoteAgentService: IRemoteAgentService, logService: ILogService): Promise { - - const workspaceService = new WorkspaceService({ userSettingsResource: this.configuration.settingsUri, remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache() }, new ConfigurationFileService(fileService), remoteAgentService); - - try { - await workspaceService.initialize(payload); - - return workspaceService; - } catch (error) { - onUnexpectedError(error); - logService.error(error); - - return workspaceService; - } - } - - private async resolveWorkspaceInitializationPayload(): Promise { - - const hash = (uri: URI) => { - return crypto.subtle.digest('SHA-1', new TextEncoder().encode(uri.toString())).then(buffer => { - // https://developer.mozilla.org/en-US/docs/Web/API/SubtleCrypto/digest#Converting_a_digest_to_a_hex_string - return Array.prototype.map.call(new Uint8Array(buffer), (value: number) => `00${value.toString(16)}`.slice(-2)).join(''); - }); - }; - - // Multi-root workspace - if (this.configuration.workspaceUri) { - const id = await hash(this.configuration.workspaceUri); - return { id, configPath: this.configuration.workspaceUri }; - } - - // Single-folder workspace - if (this.configuration.folderUri) { - const id = await hash(this.configuration.folderUri); - return { id, folder: this.configuration.folderUri }; - } - - return { id: 'empty-window' }; - } } -export interface IWindowConfigurationContents { - settingsPath: string; - folderPath?: string; - workspacePath?: string; -} +export function main(): Promise { + const renderer = new CodeRendererMain(); -export function main(windowConfigurationContents: IWindowConfigurationContents): Promise { - const windowConfiguration: IWindowConfiguration = { - settingsUri: toResource(windowConfigurationContents.settingsPath), - folderUri: windowConfigurationContents.folderPath ? toResource(windowConfigurationContents.folderPath) : undefined, - workspaceUri: windowConfigurationContents.workspacePath ? toResource(windowConfigurationContents.workspacePath) : undefined, - remoteAuthority: document.location.host - }; - const renderer = new CodeRendererMain(windowConfiguration); return renderer.open(); } - -function toResource(path: string): URI { - return URI.from({ - scheme: Schemas.vscodeRemote, - authority: document.location.host, - path - }); -} diff --git a/src/vs/workbench/browser/web.resources.ts b/src/vs/workbench/browser/web.resources.ts deleted file mode 100644 index ea43363f0c..0000000000 --- a/src/vs/workbench/browser/web.resources.ts +++ /dev/null @@ -1,98 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IFileService } from 'vs/platform/files/common/files'; -import { URI } from 'vs/base/common/uri'; - -export class WebResources { - - private readonly _regexp = /url\(('|")?(vscode-remote:\/\/.*?)\1\)/g; - private readonly _cache = new Map(); - private readonly _observer: MutationObserver; - - constructor(@IFileService private readonly _fileService: IFileService) { - this._observer = new MutationObserver(r => this._handleMutation(r)); - - // todo@joh add observer to more than head-element - // todo@joh explore alternative approach - this._observer.observe(document.head, { subtree: true, childList: true }); - } - - dispose(): void { - this._observer.disconnect(); - this._cache.forEach(value => URL.revokeObjectURL(value)); - } - - private _handleMutation(records: MutationRecord[]): void { - for (const record of records) { - if (record.target.nodeName === 'STYLE') { - // style-element directly modified - this._handleStyleNode(record.target); - - } else if (record.target.nodeName === 'HEAD' && record.type === 'childList') { - // style-element added to head - record.addedNodes.forEach(node => { - if (node.nodeName === 'STYLE') { - this._handleStyleNode(node); - } - }); - } - } - } - - private _handleStyleNode(target: Node): void { - - if (!target.textContent) { - return; - } - - const positions: number[] = []; - const promises: Promise[] = []; - - let match: RegExpMatchArray | null = null; - while (match = this._regexp.exec(target.textContent)) { - - const remoteUrl = match[2]; - positions.push(match.index! + 'url('.length + match[1].length); - positions.push(remoteUrl.length); - - if (this._cache.has(remoteUrl)) { - promises.push(Promise.resolve()); - - } else { - promises.push(this._fileService.readFile(URI.parse(remoteUrl, true)).then(file => { - // todo@joh hack - const type = /\.woff$/.test(remoteUrl) ? 'application/font-woff' : 'image/svg+xml'; - this._cache.set(remoteUrl, URL.createObjectURL(new Blob([file.value.buffer], { type }))); - })); - } - } - - if (promises.length === 0) { - return; - } - - let content = target.textContent; - - Promise.all(promises).then(() => { - - if (target.textContent !== content) { - return; - } - - for (let i = positions.length - 1; i >= 0; i -= 2) { - const start = positions[i - 1]; - const len = positions[i]; - const url = this._cache.get(content.substr(start, len)); - content = content.substring(0, start) + url + content.substring(start + len); - } - - target.textContent = content; - - }).catch(e => { - console.error(e); - }); - } -} diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index b2925f3e09..5d8b22e82c 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -13,13 +13,14 @@ import { Event } from 'vs/base/common/event'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; // tslint:disable-next-line: import-patterns no-standalone-editor -import { StandaloneKeybindingService, SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices'; +import { SimpleConfigurationService as StandaloneEditorConfigurationService, StandaloneKeybindingService, SimpleResourcePropertiesService } from 'vs/editor/standalone/browser/simpleServices'; import { IDownloadService } from 'vs/platform/download/common/download'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionHostDebugParams, IDebugParams } from 'vs/platform/environment/common/environment'; import { IExtensionGalleryService, IQueryOptions, IGalleryExtension, InstallOperation, StatisticType, ITranslation, IGalleryExtensionVersion, IExtensionIdentifier, IReportedExtension, IExtensionManagementService, ILocalExtension, IGalleryMetadata, IExtensionTipsService, ExtensionRecommendationReason, IExtensionRecommendation, IExtensionEnablementService, EnablementState } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IPager } from 'vs/base/common/paging'; import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions'; +import { NullExtensionService, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; @@ -28,7 +29,9 @@ import { INotificationService } from 'vs/platform/notification/common/notificati import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; import { ILogService, LogLevel, ConsoleLogService } from 'vs/platform/log/common/log'; import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { IMenubarService, IMenubarData } from 'vs/platform/menubar/common/menubar'; import { IProductService } from 'vs/platform/product/common/product'; +import { isEqualOrParent, isEqual } from 'vs/base/common/resources'; import { ISearchService, ITextQueryProps, ISearchProgressItem, ISearchComplete, IFileQueryProps, SearchProviderType, ISearchResultProvider, ITextQuery, IFileMatch, QueryType, FileMatch, pathIncludedInQuery } from 'vs/workbench/services/search/common/search'; import { IModelService } from 'vs/editor/common/services/modelService'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; @@ -38,37 +41,29 @@ import { Schemas } from 'vs/base/common/network'; import { editorMatchesToTextSearchResults, addContextToEditorMatches } from 'vs/workbench/services/search/common/searchHelpers'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { InMemoryStorageService, IStorageService } from 'vs/platform/storage/common/storage'; +import { ITextMateService, IGrammar as ITextMategrammar } from 'vs/workbench/services/textMate/common/textMateService'; +import { LanguageId, TokenizationRegistry } from 'vs/editor/common/modes'; import { IUpdateService, State } from 'vs/platform/update/common/update'; import { IWindowConfiguration, IPath, IPathsToWaitFor, IWindowService, INativeOpenDialogOptions, IEnterWorkspaceResult, IURIToOpen, IMessageBoxResult, IWindowsService, IOpenSettings } from 'vs/platform/windows/common/windows'; import { IProcessEnvironment } from 'vs/base/common/platform'; -import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; +import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier, IWorkspaceFolderCreationData, isSingleFolderWorkspaceIdentifier, IWorkspacesService } from 'vs/platform/workspaces/common/workspaces'; import { ExportData } from 'vs/base/common/performance'; import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history'; import { ISerializableCommandAction } from 'vs/platform/actions/common/actions'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; +import { IWorkspaceContextService, Workspace, toWorkspaceFolder, IWorkspaceFolder, WorkbenchState, IWorkspace } from 'vs/platform/workspace/common/workspace'; import { ITextResourcePropertiesService } from 'vs/editor/common/services/resourceConfiguration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { Color, RGBA } from 'vs/base/common/color'; import { ITunnelService } from 'vs/platform/remote/common/tunnel'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IFileService } from 'vs/platform/files/common/files'; -import { IReloadSessionEvent, IExtensionHostDebugService, ICloseSessionEvent, IAttachSessionEvent, ILogToSessionEvent, ITerminateSessionEvent } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { IRemoteConsoleLog } from 'vs/base/common/console'; -// tslint:disable-next-line: import-patterns -import { State as DebugState, IDebugService, IDebugSession, IConfigurationManager, IStackFrame, IThread, IViewModel, IExpression, IFunctionBreakpoint } from 'vs/workbench/contrib/debug/common/debug'; -// tslint:disable-next-line: import-patterns -import { IExtensionsWorkbenchService, IExtension as IExtension2 } from 'vs/workbench/contrib/extensions/common/extensions'; -// tslint:disable-next-line: import-patterns -import { ITerminalService, ITerminalConfigHelper, ITerminalTab, ITerminalInstance, ITerminalProcessExtHostRequest } from 'vs/workbench/contrib/terminal/common/terminal'; -// tslint:disable-next-line: import-patterns -import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; -// tslint:disable-next-line: import-patterns -import { TaskEvent } from 'vs/workbench/contrib/tasks/common/tasks'; -// tslint:disable-next-line: import-patterns -import { ICommentService, IResourceCommentThreadEvent, IWorkspaceCommentThreadsEvent } from 'vs/workbench/contrib/comments/browser/commentService'; -// tslint:disable-next-line: import-patterns -import { ICommentThreadChangedEvent } from 'vs/workbench/contrib/comments/common/commentModel'; -import { CommentingRanges } from 'vs/editor/common/modes'; -import { Range } from 'vs/editor/common/core/range'; + +export const workspaceResource = URI.file((self).USER_HOME_DIR || '/').with({ + scheme: Schemas.vscodeRemote, + authority: document.location.host +}); //#region Backup File @@ -132,6 +127,36 @@ registerSingleton(IBackupFileService, SimpleBackupFileService, true); //#endregion +//#region Broadcast + +export const IBroadcastService = createDecorator('broadcastService'); + +export interface IBroadcast { + channel: string; + payload: any; +} + +export interface IBroadcastService { + _serviceBrand: any; + + onBroadcast: Event; + + broadcast(b: IBroadcast): void; +} + +export class SimpleBroadcastService implements IBroadcastService { + + _serviceBrand: any; + + readonly onBroadcast: Event = Event.None; + + broadcast(b: IBroadcast): void { } +} + +registerSingleton(IBroadcastService, SimpleBroadcastService, true); + +//#endregion + //#region Clipboard export class SimpleClipboardService implements IClipboardService { @@ -167,6 +192,14 @@ registerSingleton(IClipboardService, SimpleClipboardService, true); //#endregion +//#region Configuration + +export class SimpleConfigurationService extends StandaloneEditorConfigurationService { } + +registerSingleton(IConfigurationService, SimpleConfigurationService); + +//#endregion + //#region Dialog // export class SimpleDialogService extends StandaloneEditorDialogService { } @@ -198,17 +231,17 @@ export class SimpleWorkbenchEnvironmentService implements IWorkbenchEnvironmentS untitledWorkspacesHome: URI; extensionTestsLocationURI?: URI; _serviceBrand: any; - args: any; + args = { _: [] }; execPath: string; cliPath: string; - appRoot: string; + appRoot: string = '/web/'; userHome: string; userDataPath: string; appNameLong: string; appQuality?: string; - appSettingsHome: string; - settingsResource: URI; - appKeybindingsPath: string; + appSettingsHome: string = '/web/settings'; + appSettingsPath: string = '/web/settings/settings.json'; + appKeybindingsPath: string = '/web/settings/keybindings.json'; machineSettingsHome: string; machineSettingsPath: string; settingsSearchBuildId?: number; @@ -231,7 +264,7 @@ export class SimpleWorkbenchEnvironmentService implements IWorkbenchEnvironmentS wait: boolean; status: boolean; log?: string; - logsPath: string; + logsPath: string = '/web/logs'; verbose: boolean; skipGettingStarted: boolean; skipReleaseNotes: boolean; @@ -317,235 +350,6 @@ registerSingleton(IExtensionGalleryService, SimpleExtensionGalleryService, true) //#endregion -//#region IDebugService -export class SimpleDebugService implements IDebugService { - _serviceBrand: any; - state: DebugState; - onDidChangeState: Event = Event.None; - onDidNewSession: Event = Event.None; - onWillNewSession: Event = Event.None; - onDidEndSession: Event = Event.None; - getConfigurationManager(): IConfigurationManager { - return new class implements IConfigurationManager { - canSetBreakpointsIn: any; - selectedConfiguration: any; - selectConfiguration: any; - getLaunches: any; - getLaunch: any; - onDidSelectConfiguration: Event; - activateDebuggers: any; - hasDebugConfigurationProvider: any; - registerDebugConfigurationProvider: any; - unregisterDebugConfigurationProvider: any; - registerDebugAdapterDescriptorFactory: any; - unregisterDebugAdapterDescriptorFactory: any; - resolveConfigurationByProviders: any; - getDebugAdapterDescriptor: any; - registerDebugAdapterFactory() { return Disposable.None; } - createDebugAdapter: any; - substituteVariables: any; - runInTerminal: any; - }; - } - focusStackFrame: any; - addBreakpoints: any; - updateBreakpoints: any; - enableOrDisableBreakpoints: any; - setBreakpointsActivated: any; - removeBreakpoints: any; - addFunctionBreakpoint: any; - renameFunctionBreakpoint: any; - removeFunctionBreakpoints: any; - sendAllBreakpoints: any; - addWatchExpression: any; - renameWatchExpression: any; - moveWatchExpression: any; - removeWatchExpressions: any; - startDebugging: any; - restartSession: any; - stopSession: any; - sourceIsNotAvailable: any; - getModel: any; - getViewModel(): IViewModel { - return new class implements IViewModel { - focusedSession: IDebugSession | undefined; - focusedThread: IThread | undefined; - focusedStackFrame: IStackFrame | undefined; - getSelectedExpression(): IExpression | undefined { - throw new Error('Method not implemented.'); - } - getSelectedFunctionBreakpoint(): IFunctionBreakpoint | undefined { - throw new Error('Method not implemented.'); - } - setSelectedExpression(expression: IExpression | undefined): void { - throw new Error('Method not implemented.'); - } - setSelectedFunctionBreakpoint(functionBreakpoint: IFunctionBreakpoint | undefined): void { - throw new Error('Method not implemented.'); - } - isMultiSessionView(): boolean { - throw new Error('Method not implemented.'); - } - onDidFocusSession: Event = Event.None; - onDidFocusStackFrame: Event<{ stackFrame: IStackFrame | undefined; explicit: boolean; }> = Event.None; - onDidSelectExpression: Event = Event.None; - getId(): string { - throw new Error('Method not implemented.'); - } - }; - } -} -registerSingleton(IDebugService, SimpleDebugService, true); - -//#endregion IExtensionsWorkbenchService -export class SimpleExtensionsWorkbenchService implements IExtensionsWorkbenchService { - _serviceBrand: any; - onChange: Event; - local: IExtension2[]; - installed: IExtension2[]; - outdated: IExtension2[]; - queryLocal: any; - queryGallery: any; - canInstall: any; - install: any; - uninstall: any; - installVersion: any; - reinstall: any; - setEnablement: any; - open: any; - checkForUpdates: any; - allowedBadgeProviders: string[]; -} -registerSingleton(IExtensionsWorkbenchService, SimpleExtensionsWorkbenchService, true); -//#endregion - -//#region ITerminalService -export class SimpleTerminalService implements ITerminalService { - _serviceBrand: any; activeTabIndex: number; - configHelper: ITerminalConfigHelper; - onActiveTabChanged: Event = Event.None; - onTabDisposed: Event = Event.None; - onInstanceCreated: Event = Event.None; - onInstanceDisposed: Event = Event.None; - onInstanceProcessIdReady: Event = Event.None; - onInstanceDimensionsChanged: Event = Event.None; - onInstanceRequestExtHostProcess: Event = Event.None; - onInstancesChanged: Event = Event.None; - onInstanceTitleChanged: Event = Event.None; - onActiveInstanceChanged: Event = Event.None; - terminalInstances: ITerminalInstance[] = []; - terminalTabs: ITerminalTab[]; - createTerminal: any; - createTerminalRenderer: any; - createInstance: any; - getInstanceFromId: any; - getInstanceFromIndex: any; - getTabLabels: any; - getActiveInstance() { return null; } - setActiveInstance: any; - setActiveInstanceByIndex: any; - getActiveOrCreateInstance: any; - splitInstance: any; - getActiveTab: any; - setActiveTabToNext: any; - setActiveTabToPrevious: any; - setActiveTabByIndex: any; - refreshActiveTab: any; - showPanel: any; - hidePanel: any; - focusFindWidget: any; - hideFindWidget: any; - getFindState: any; - findNext: any; - findPrevious: any; - setContainers: any; - getDefaultShell: any; - selectDefaultWindowsShell: any; - setWorkspaceShellAllowed: any; - preparePathForTerminalAsync: any; - extHostReady() { } - requestExtHostProcess: any; -} -registerSingleton(ITerminalService, SimpleTerminalService, true); - -//#endregion - -//#region ITaskService -export class SimpleTaskService implements ITaskService { - _serviceBrand: any; - onDidStateChange: Event = Event.None; - supportsMultipleTaskExecutions: boolean; - configureAction: any; - build: any; - runTest: any; - run: any; - inTerminal: any; - isActive: any; - getActiveTasks: any; - restart: any; - terminate: any; - terminateAll: any; - tasks: any; - getWorkspaceTasks: any; - getTask: any; - getTasksForGroup: any; - getRecentlyUsedTasks: any; - createSorter: any; - needsFolderQualification: any; - canCustomize: any; - customize: any; - openConfig: any; - registerTaskProvider() { return Disposable.None; } - registerTaskSystem() { } - extensionCallbackTaskComplete: any; -} -registerSingleton(ITaskService, SimpleTaskService, true); -//#endregion - -//#region ICommentService -export class SimpleCommentService implements ICommentService { - _serviceBrand: any; - onDidSetResourceCommentInfos: Event = Event.None; - onDidSetAllCommentThreads: Event = Event.None; - onDidUpdateCommentThreads: Event = Event.None; - onDidChangeActiveCommentingRange: Event<{ range: Range; commentingRangesInfo: CommentingRanges; }> = Event.None; - onDidChangeActiveCommentThread: Event = Event.None; - onDidSetDataProvider: Event = Event.None; - onDidDeleteDataProvider: Event = Event.None; - setDocumentComments: any; - setWorkspaceComments: any; - removeWorkspaceComments: any; - registerCommentController: any; - unregisterCommentController: any; - getCommentController: any; - createCommentThreadTemplate: any; - updateCommentThreadTemplate: any; - getCommentMenus: any; - registerDataProvider: any; - unregisterDataProvider: any; - updateComments: any; - disposeCommentThread: any; - createNewCommentThread: any; - replyToCommentThread: any; - editComment: any; - deleteComment: any; - getComments() { return Promise.resolve([]); } - getCommentingRanges: any; - startDraft: any; - deleteDraft: any; - finishDraft: any; - getStartDraftLabel: any; - getDeleteDraftLabel: any; - getFinishDraftLabel: any; - addReaction: any; - deleteReaction: any; - getReactionGroup: any; - toggleReaction: any; - setActiveCommentThread: any; -} -registerSingleton(ICommentService, SimpleCommentService, true); -//#endregion - //#region Extension Management //#region Extension Enablement @@ -556,10 +360,10 @@ export class SimpleExtensionEnablementService implements IExtensionEnablementSer readonly onEnablementChanged = Event.None; - readonly allUserExtensionsDisabled = false; + readonly allUserExtensionsDisabled = true; getEnablementState(extension: IExtension): EnablementState { - return EnablementState.Enabled; + return EnablementState.Disabled; } canChangeEnablement(extension: IExtension): boolean { @@ -571,7 +375,7 @@ export class SimpleExtensionEnablementService implements IExtensionEnablementSer } isEnabled(extension: IExtension): boolean { - return true; + return false; } } @@ -675,6 +479,14 @@ registerSingleton(IExtensionManagementService, SimpleExtensionManagementService) //#endregion +//#region Extensions + +export class SimpleExtensionService extends NullExtensionService { } + +registerSingleton(IExtensionService, SimpleExtensionService); + +//#endregion + //#region Extension URL Handler export const IExtensionUrlHandler = createDecorator('inactiveExtensionUrlHandler'); @@ -770,6 +582,21 @@ export class SimpleLogService extends ConsoleLogService { } //#endregion +//#region Menu Bar + +export class SimpleMenubarService implements IMenubarService { + + _serviceBrand: any; + + updateMenubar(windowId: number, menuData: IMenubarData): Promise { + return Promise.resolve(undefined); + } +} + +registerSingleton(IMenubarService, SimpleMenubarService); + +//#endregion + //#region Multi Extension Management export class SimpleMultiExtensionsManagementService implements IExtensionManagementService { @@ -832,12 +659,9 @@ export class SimpleProductService implements IProductService { _serviceBrand: any; - version: string = '1.35.0'; + version?: string; commit?: string; - nameLong: string = ''; - urlProtocol: string = ''; - extensionAllowedProposedApi: string[] = []; - uiExtensions?: string[]; + enableTelemetry: boolean = false; } @@ -997,6 +821,26 @@ registerSingleton(ITelemetryService, SimpleTelemetryService); //#endregion +//#region Textmate + +TokenizationRegistry.setColorMap([null, new Color(new RGBA(212, 212, 212, 1)), new Color(new RGBA(30, 30, 30, 1))]); + +export class SimpleTextMateService implements ITextMateService { + + _serviceBrand: any; + + readonly onDidEncounterLanguage: Event = Event.None; + + createGrammar(modeId: string): Promise { + // @ts-ignore + return Promise.resolve(undefined); + } +} + +registerSingleton(ITextMateService, SimpleTextMateService, true); + +//#endregion + //#region Text Resource Properties export class SimpleTextResourcePropertiesService extends SimpleResourcePropertiesService { } @@ -1079,7 +923,7 @@ export class SimpleWindowConfiguration implements IWindowConfiguration { workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; - remoteAuthority: string = document.location.host; + remoteAuthority?: string; zoomLevel?: number; fullscreen?: boolean; @@ -1227,30 +1071,6 @@ registerSingleton(IWindowService, SimpleWindowService); //#endregion -//#region ExtensionHostDebugService - -export class SimpleExtensionHostDebugService implements IExtensionHostDebugService { - _serviceBrand: any; - - reload(sessionId: string): void { } - onReload: Event = Event.None; - - close(sessionId: string): void { } - onClose: Event = Event.None; - - attachSession(sessionId: string, port: number, subId?: string): void { } - onAttachSession: Event = Event.None; - - logToSession(sessionId: string, log: IRemoteConsoleLog): void { } - onLogToSession: Event = Event.None; - - terminateSession(sessionId: string, subId?: string): void { } - onTerminateSession: Event = Event.None; -} -registerSingleton(IExtensionHostDebugService, SimpleExtensionHostDebugService); - -//#endregion - //#region Window export class SimpleWindowsService implements IWindowsService { @@ -1517,6 +1337,66 @@ registerSingleton(IWorkspaceEditingService, SimpleWorkspaceEditingService, true) //#endregion +//#region Workspace + +export class SimpleWorkspaceService implements IWorkspaceContextService { + _serviceBrand: any; + + private workspace: Workspace; + + readonly onDidChangeWorkspaceName = Event.None; + readonly onDidChangeWorkspaceFolders = Event.None; + readonly onDidChangeWorkbenchState = Event.None; + + constructor() { + this.workspace = new Workspace(workspaceResource.toString(), [toWorkspaceFolder(workspaceResource)]); + } + + getFolders(): IWorkspaceFolder[] { + return this.workspace ? this.workspace.folders : []; + } + + getWorkbenchState(): WorkbenchState { + if (this.workspace.configuration) { + return WorkbenchState.WORKSPACE; + } + + if (this.workspace.folders.length) { + return WorkbenchState.FOLDER; + } + + return WorkbenchState.EMPTY; + } + + getCompleteWorkspace(): Promise { + return Promise.resolve(this.getWorkspace()); + } + + getWorkspace(): IWorkspace { + return this.workspace; + } + + getWorkspaceFolder(resource: URI): IWorkspaceFolder | null { + return this.workspace.getFolder(resource); + } + + isInsideWorkspace(resource: URI): boolean { + if (resource && this.workspace) { + return isEqualOrParent(resource, this.workspace.folders[0].uri); + } + + return false; + } + + isCurrentWorkspace(workspaceIdentifier: ISingleFolderWorkspaceIdentifier | IWorkspaceIdentifier): boolean { + return isSingleFolderWorkspaceIdentifier(workspaceIdentifier) && isEqual(this.workspace.folders[0].uri, workspaceIdentifier); + } +} + +registerSingleton(IWorkspaceContextService, SimpleWorkspaceService); + +//#endregion + //#region Workspaces export class SimpleWorkspacesService implements IWorkspacesService { diff --git a/src/vs/workbench/browser/workbench.contribution.ts b/src/vs/workbench/browser/workbench.contribution.ts index 1df527c99e..4d89f096e8 100644 --- a/src/vs/workbench/browser/workbench.contribution.ts +++ b/src/vs/workbench/browser/workbench.contribution.ts @@ -180,12 +180,6 @@ import { isMacintosh } from 'vs/base/common/platform'; 'default': true, 'description': nls.localize('activityBarVisibility', "Controls the visibility of the activity bar in the workbench.") }, - // TODO @misolori remove before shipping stable - 'workbench.iconExploration.enabled': { - 'type': 'boolean', - 'default': false, - 'description': nls.localize('iconExplorationEnabled', "Controls the visibility of the icon exploration in the workbench.") - }, 'workbench.view.alwaysShowHeaderActions': { 'type': 'boolean', 'default': false, diff --git a/src/vs/workbench/browser/workbench.ts b/src/vs/workbench/browser/workbench.ts index 0e4c78e686..fd7bcdb15d 100644 --- a/src/vs/workbench/browser/workbench.ts +++ b/src/vs/workbench/browser/workbench.ts @@ -267,7 +267,6 @@ export class Workbench extends Layout { const workbenchClasses = coalesce([ 'monaco-workbench', platformClass, - isWeb ? 'web' : undefined, this.state.sideBar.hidden ? 'nosidebar' : undefined, this.state.panel.hidden ? 'nopanel' : undefined, this.state.statusBar.hidden ? 'nostatusbar' : undefined, diff --git a/src/vs/workbench/common/actions.ts b/src/vs/workbench/common/actions.ts index 51eb00557b..14b786ff74 100644 --- a/src/vs/workbench/common/actions.ts +++ b/src/vs/workbench/common/actions.ts @@ -8,7 +8,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { ICommandHandler, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { SyncActionDescriptor, MenuRegistry, MenuId, ICommandAction } from 'vs/platform/actions/common/actions'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; @@ -33,10 +33,10 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR } private registerWorkbenchCommandFromAction(descriptor: SyncActionDescriptor, alias: string, category?: string, when?: ContextKeyExpr): IDisposable { - const registrations = new DisposableStore(); + let registrations: IDisposable[] = []; // command - registrations.add(CommandsRegistry.registerCommand(descriptor.id, this.createCommandHandler(descriptor))); + registrations.push(CommandsRegistry.registerCommand(descriptor.id, this.createCommandHandler(descriptor))); // keybinding const weight = (typeof descriptor.keybindingWeight === 'undefined' ? KeybindingWeight.WorkbenchContrib : descriptor.keybindingWeight); @@ -72,13 +72,13 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR MenuRegistry.addCommand(command); - registrations.add(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when })); + registrations.push(MenuRegistry.appendMenuItem(MenuId.CommandPalette, { command, when })); } // TODO@alex,joh // support removal of keybinding rule // support removal of command-ui - return registrations; + return combinedDisposable(registrations); } private createCommandHandler(descriptor: SyncActionDescriptor): ICommandHandler { diff --git a/src/vs/workbench/common/component.ts b/src/vs/workbench/common/component.ts index b758771624..c956882eaf 100644 --- a/src/vs/workbench/common/component.ts +++ b/src/vs/workbench/common/component.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Memento, MementoObject } from 'vs/workbench/common/memento'; +import { Memento } from 'vs/workbench/common/memento'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { Themable } from 'vs/workbench/common/theme'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -35,7 +35,7 @@ export class Component extends Themable { return this.id; } - protected getMemento(scope: StorageScope): MementoObject { + protected getMemento(scope: StorageScope): object { return this.memento.getMemento(scope); } diff --git a/src/vs/workbench/common/composite.ts b/src/vs/workbench/common/composite.ts index a6e6a00c8a..c3a6e06937 100644 --- a/src/vs/workbench/common/composite.ts +++ b/src/vs/workbench/common/composite.ts @@ -20,17 +20,17 @@ export interface IComposite { /** * Returns the primary actions of the composite. */ - getActions(): ReadonlyArray; + getActions(): IAction[]; /** * Returns the secondary actions of the composite. */ - getSecondaryActions(): ReadonlyArray; + getSecondaryActions(): IAction[]; /** * Returns an array of actions to show in the context menu of the composite */ - getContextMenuActions(): ReadonlyArray; + getContextMenuActions(): IAction[]; /** * Returns the action item for a specific action. diff --git a/src/vs/workbench/common/editor.ts b/src/vs/workbench/common/editor.ts index dcdf92395d..772939fa74 100644 --- a/src/vs/workbench/common/editor.ts +++ b/src/vs/workbench/common/editor.ts @@ -23,9 +23,7 @@ import { coalesce } from 'vs/base/common/arrays'; export const ActiveEditorContext = new RawContextKey('activeEditor', null); export const EditorsVisibleContext = new RawContextKey('editorIsOpen', false); -export const EditorPinnedContext = new RawContextKey('editorPinned', false); export const EditorGroupActiveEditorDirtyContext = new RawContextKey('groupActiveEditorDirty', false); -export const EditorGroupEditorsCountContext = new RawContextKey('groupEditorsCount', 0); export const NoEditorsVisibleContext: ContextKeyExpr = EditorsVisibleContext.toNegated(); export const TextCompareEditorVisibleContext = new RawContextKey('textCompareEditorVisible', false); export const TextCompareEditorActiveContext = new RawContextKey('textCompareEditorActive', false); @@ -33,7 +31,6 @@ export const ActiveEditorGroupEmptyContext = new RawContextKey('activeE export const MultipleEditorGroupsContext = new RawContextKey('multipleEditorGroups', false); export const SingleEditorGroupsContext = MultipleEditorGroupsContext.toNegated(); export const InEditorZenModeContext = new RawContextKey('inZenMode', false); -export const IsCenteredLayoutContext = new RawContextKey('isCenteredLayout', false); export const SplitEditorsVertically = new RawContextKey('splitEditorsVertically', false); /** @@ -178,7 +175,7 @@ export interface IEditorInputFactoryRegistry { * * @param editorInputId the identifier of the editor input */ - getEditorInputFactory(editorInputId: string): IEditorInputFactory | undefined; + getEditorInputFactory(editorInputId: string): IEditorInputFactory; /** * Starts the registry by providing the required services. @@ -1061,22 +1058,23 @@ export interface IEditorMemento { class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { private instantiationService: IInstantiationService; private fileInputFactory: IFileInputFactory; - private readonly editorInputFactoryConstructors: Map> = new Map(); - private readonly editorInputFactoryInstances: Map = new Map(); + private editorInputFactoryConstructors: { [editorInputId: string]: IConstructorSignature0 } = Object.create(null); + private readonly editorInputFactoryInstances: { [editorInputId: string]: IEditorInputFactory } = Object.create(null); start(accessor: ServicesAccessor): void { this.instantiationService = accessor.get(IInstantiationService); - this.editorInputFactoryConstructors.forEach((ctor, key) => { - this.createEditorInputFactory(key, ctor); - }); + for (let key in this.editorInputFactoryConstructors) { + const element = this.editorInputFactoryConstructors[key]; + this.createEditorInputFactory(key, element); + } - this.editorInputFactoryConstructors.clear(); + this.editorInputFactoryConstructors = Object.create(null); } private createEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { const instance = this.instantiationService.createInstance(ctor); - this.editorInputFactoryInstances.set(editorInputId, instance); + this.editorInputFactoryInstances[editorInputId] = instance; } registerFileInputFactory(factory: IFileInputFactory): void { @@ -1089,14 +1087,14 @@ class EditorInputFactoryRegistry implements IEditorInputFactoryRegistry { registerEditorInputFactory(editorInputId: string, ctor: IConstructorSignature0): void { if (!this.instantiationService) { - this.editorInputFactoryConstructors.set(editorInputId, ctor); + this.editorInputFactoryConstructors[editorInputId] = ctor; } else { this.createEditorInputFactory(editorInputId, ctor); } } - getEditorInputFactory(editorInputId: string): IEditorInputFactory | undefined { - return this.editorInputFactoryInstances.get(editorInputId); + getEditorInputFactory(editorInputId: string): IEditorInputFactory { + return this.editorInputFactoryInstances[editorInputId]; } } diff --git a/src/vs/workbench/common/editor/resourceEditorInput.ts b/src/vs/workbench/common/editor/resourceEditorInput.ts index 6905289180..25ef75d54f 100644 --- a/src/vs/workbench/common/editor/resourceEditorInput.ts +++ b/src/vs/workbench/common/editor/resourceEditorInput.ts @@ -90,7 +90,7 @@ export class ResourceEditorInput extends EditorInput implements IModeSupport { ref.dispose(); this.modelReference = null; - throw new Error(`Unexpected model for ResourceInput: ${this.resource}`); + return Promise.reject(new Error(`Unexpected model for ResourceInput: ${this.resource}`)); } this.cachedModel = model; diff --git a/src/vs/workbench/common/memento.ts b/src/vs/workbench/common/memento.ts index 7e3cb895ed..7f1e366d88 100644 --- a/src/vs/workbench/common/memento.ts +++ b/src/vs/workbench/common/memento.ts @@ -6,12 +6,10 @@ import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { isEmptyObject } from 'vs/base/common/types'; -export type MementoObject = { [key: string]: any }; - export class Memento { - private static readonly globalMementos = new Map(); - private static readonly workspaceMementos = new Map(); + private static globalMementos: { [id: string]: ScopedMemento } = Object.create(null); + private static workspaceMementos: { [id: string]: ScopedMemento } = Object.create(null); private static readonly COMMON_PREFIX = 'memento/'; @@ -21,24 +19,24 @@ export class Memento { this.id = Memento.COMMON_PREFIX + id; } - getMemento(scope: StorageScope): MementoObject { + getMemento(scope: StorageScope): object { // Scope by Workspace if (scope === StorageScope.WORKSPACE) { - let workspaceMemento = Memento.workspaceMementos.get(this.id); + let workspaceMemento = Memento.workspaceMementos[this.id]; if (!workspaceMemento) { workspaceMemento = new ScopedMemento(this.id, scope, this.storageService); - Memento.workspaceMementos.set(this.id, workspaceMemento); + Memento.workspaceMementos[this.id] = workspaceMemento; } return workspaceMemento.getMemento(); } // Scope Global - let globalMemento = Memento.globalMementos.get(this.id); + let globalMemento = Memento.globalMementos[this.id]; if (!globalMemento) { globalMemento = new ScopedMemento(this.id, scope, this.storageService); - Memento.globalMementos.set(this.id, globalMemento); + Memento.globalMementos[this.id] = globalMemento; } return globalMemento.getMemento(); @@ -47,13 +45,13 @@ export class Memento { saveMemento(): void { // Workspace - const workspaceMemento = Memento.workspaceMementos.get(this.id); + const workspaceMemento = Memento.workspaceMementos[this.id]; if (workspaceMemento) { workspaceMemento.save(); } // Global - const globalMemento = Memento.globalMementos.get(this.id); + const globalMemento = Memento.globalMementos[this.id]; if (globalMemento) { globalMemento.save(); } @@ -61,17 +59,17 @@ export class Memento { } class ScopedMemento { - private readonly mementoObj: MementoObject; + private readonly mementoObj: object; constructor(private id: string, private scope: StorageScope, private storageService: IStorageService) { this.mementoObj = this.load(); } - getMemento(): MementoObject { + getMemento(): object { return this.mementoObj; } - private load(): MementoObject { + private load(): object { const memento = this.storageService.get(this.id, this.scope); if (memento) { return JSON.parse(memento); diff --git a/src/vs/workbench/common/notifications.ts b/src/vs/workbench/common/notifications.ts index 6cac2f86b1..2ee1ceefff 100644 --- a/src/vs/workbench/common/notifications.ts +++ b/src/vs/workbench/common/notifications.ts @@ -3,10 +3,10 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotification, INotificationHandle, INotificationActions, INotificationProgress, NoOpNotification, Severity, NotificationMessage, IPromptChoice } from 'vs/platform/notification/common/notification'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Event, Emitter } from 'vs/base/common/event'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { isPromiseCanceledError } from 'vs/base/common/errors'; import { Action } from 'vs/base/common/actions'; import { isErrorWithActions } from 'vs/base/common/errorsWithActions'; @@ -15,25 +15,10 @@ import { localize } from 'vs/nls'; export interface INotificationsModel { - // - // Notifications as Toasts/Center - // - readonly notifications: INotificationViewItem[]; - readonly onDidNotificationChange: Event; - addNotification(notification: INotification): INotificationHandle; - - // - // Notifications as Status - // - - readonly statusMessage: IStatusMessageViewItem | undefined; - - readonly onDidStatusMessageChange: Event; - - showStatusMessage(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable; + notify(notification: INotification): INotificationHandle; } export const enum NotificationChangeType { @@ -60,29 +45,6 @@ export interface INotificationChangeEvent { kind: NotificationChangeType; } -export const enum StatusMessageChangeType { - ADD, - REMOVE -} - -export interface IStatusMessageViewItem { - message: string; - options?: IStatusMessageOptions; -} - -export interface IStatusMessageChangeEvent { - - /** - * The status message item this change is about. - */ - item: IStatusMessageViewItem; - - /** - * The kind of status message change. - */ - kind: StatusMessageChangeType; -} - export class NotificationHandle implements INotificationHandle { private readonly _onDidClose: Emitter = new Emitter(); @@ -128,16 +90,13 @@ export class NotificationsModel extends Disposable implements INotificationsMode private readonly _onDidNotificationChange: Emitter = this._register(new Emitter()); get onDidNotificationChange(): Event { return this._onDidNotificationChange.event; } - private readonly _onDidStatusMessageChange: Emitter = this._register(new Emitter()); - get onDidStatusMessageChange(): Event { return this._onDidStatusMessageChange.event; } - private readonly _notifications: INotificationViewItem[] = []; - get notifications(): INotificationViewItem[] { return this._notifications; } - private _statusMessage: IStatusMessageViewItem | undefined; - get statusMessage(): IStatusMessageViewItem | undefined { return this._statusMessage; } + get notifications(): INotificationViewItem[] { + return this._notifications; + } - addNotification(notification: INotification): INotificationHandle { + notify(notification: INotification): INotificationHandle { const item = this.createViewItem(notification); if (!item) { return NotificationsModel.NO_OP_NOTIFICATION; // return early if this is a no-op @@ -215,26 +174,6 @@ export class NotificationsModel extends Disposable implements INotificationsMode return item; } - - showStatusMessage(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable { - const item = StatusMessageViewItem.create(message, options); - if (!item) { - return Disposable.None; - } - - // Remember as current status message and fire events - this._statusMessage = item; - this._onDidStatusMessageChange.fire({ kind: StatusMessageChangeType.ADD, item }); - - return toDisposable(() => { - - // Only reset status message if the item is still the one we had remembered - if (this._statusMessage === item) { - this._statusMessage = undefined; - this._onDidStatusMessageChange.fire({ kind: StatusMessageChangeType.REMOVE, item }); - } - }); - } } export interface INotificationViewItem { @@ -682,26 +621,4 @@ export class ChoiceAction extends Action { this._onDidRun.dispose(); } -} - -class StatusMessageViewItem { - - static create(notification: NotificationMessage, options?: IStatusMessageOptions): IStatusMessageViewItem | null { - if (!notification || isPromiseCanceledError(notification)) { - return null; // we need a message to show - } - - let message: string | undefined; - if (notification instanceof Error) { - message = toErrorMessage(notification, false); - } else if (typeof notification === 'string') { - message = notification; - } - - if (!message) { - return null; // we need a message to show - } - - return { message, options }; - } } \ No newline at end of file diff --git a/src/vs/workbench/common/panel.ts b/src/vs/workbench/common/panel.ts index ed99ea8017..0600d9d787 100644 --- a/src/vs/workbench/common/panel.ts +++ b/src/vs/workbench/common/panel.ts @@ -8,6 +8,5 @@ import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const ActivePanelContext = new RawContextKey('activePanel', ''); export const PanelFocusContext = new RawContextKey('panelFocus', false); -export const PanelPositionContext = new RawContextKey('panelPosition', 'bottom'); export interface IPanel extends IComposite { } diff --git a/src/vs/workbench/common/theme.ts b/src/vs/workbench/common/theme.ts index e66ae48327..030ec18d67 100644 --- a/src/vs/workbench/common/theme.ts +++ b/src/vs/workbench/common/theme.ts @@ -30,12 +30,6 @@ export const TAB_ACTIVE_BACKGROUND = registerColor('tab.activeBackground', { hc: editorBackground }, nls.localize('tabActiveBackground', "Active tab background color. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); -export const TAB_UNFOCUSED_ACTIVE_BACKGROUND = registerColor('tab.unfocusedActiveBackground', { - dark: TAB_ACTIVE_BACKGROUND, - light: TAB_ACTIVE_BACKGROUND, - hc: TAB_ACTIVE_BACKGROUND -}, nls.localize('tabUnfocusedActiveBackground', "Active tab background color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); - export const TAB_INACTIVE_BACKGROUND = registerColor('tab.inactiveBackground', { dark: '#2D2D2D', light: '#ECECEC', @@ -144,6 +138,7 @@ export const TAB_UNFOCUSED_INACTIVE_FOREGROUND = registerColor('tab.unfocusedIna hc: Color.white }, nls.localize('tabUnfocusedInactiveForeground', "Inactive tab foreground color in an unfocused group. Tabs are the containers for editors in the editor area. Multiple tabs can be opened in one editor group. There can be multiple editor groups.")); + // < --- Editors --- > export const EDITOR_PANE_BACKGROUND = registerColor('editorPane.background', { @@ -575,4 +570,4 @@ export class Themable extends Disposable { return color ? color.toString() : null; } -} +} \ No newline at end of file diff --git a/src/vs/workbench/common/views.ts b/src/vs/workbench/common/views.ts index ce58032c37..e5c7207e32 100644 --- a/src/vs/workbench/common/views.ts +++ b/src/vs/workbench/common/views.ts @@ -11,7 +11,7 @@ import { ITreeViewDataProvider } from 'vs/workbench/common/views'; import { localize } from 'vs/nls'; import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { ThemeIcon } from 'vs/platform/theme/common/themeService'; import { values, keys } from 'vs/base/common/map'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -71,12 +71,12 @@ export class ViewContainer { protected constructor(readonly id: string, readonly hideIfEmpty: boolean, readonly extensionId?: ExtensionIdentifier) { } } -class ViewContainersRegistryImpl extends Disposable implements IViewContainersRegistry { +class ViewContainersRegistryImpl implements IViewContainersRegistry { - private readonly _onDidRegister = this._register(new Emitter()); + private readonly _onDidRegister = new Emitter(); readonly onDidRegister: Event = this._onDidRegister.event; - private readonly _onDidDeregister = this._register(new Emitter()); + private readonly _onDidDeregister = new Emitter(); readonly onDidDeregister: Event = this._onDidDeregister.event; private viewContainers: Map = new Map(); @@ -169,15 +169,15 @@ export interface IViewsRegistry { getViewContainer(id: string): ViewContainer | null; } -class ViewsRegistry extends Disposable implements IViewsRegistry { +class ViewsRegistry implements IViewsRegistry { - private readonly _onViewsRegistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._register(new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>()); + private readonly _onViewsRegistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>(); readonly onViewsRegistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._onViewsRegistered.event; - private readonly _onViewsDeregistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._register(new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>()); + private readonly _onViewsDeregistered: Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], viewContainer: ViewContainer }>(); readonly onViewsDeregistered: Event<{ views: IViewDescriptor[], viewContainer: ViewContainer }> = this._onViewsDeregistered.event; - private readonly _onDidChangeContainer: Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._register(new Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>()); + private readonly _onDidChangeContainer: Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = new Emitter<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }>(); readonly onDidChangeContainer: Event<{ views: IViewDescriptor[], from: ViewContainer, to: ViewContainer }> = this._onDidChangeContainer.event; private _viewContainers: ViewContainer[] = []; diff --git a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts index 501d3b29e5..88749118a4 100644 --- a/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts +++ b/src/vs/workbench/contrib/callHierarchy/browser/callHierarchyPeek.ts @@ -117,7 +117,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { this.create(); this._peekViewService.addExclusiveWidget(editor, this); this._applyTheme(themeService.getTheme()); - this._disposables.add(themeService.onThemeChange(this._applyTheme, this)); + themeService.onThemeChange(this._applyTheme, this, this._disposables); } dispose(): void { @@ -230,18 +230,18 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { } }, Sizing.Distribute); - this._disposables.add(this._splitView.onDidSashChange(() => { + this._splitView.onDidSashChange(() => { if (this._dim.width) { this._layoutInfo.ratio = this._splitView.getViewSize(0) / this._dim.width; } - })); + }, undefined, this._disposables); // session state let localDispose: IDisposable[] = []; - this._disposables.add({ dispose() { dispose(localDispose); } }); + this._disposables.push({ dispose() { dispose(localDispose); } }); // update editor - this._disposables.add(this._tree.onDidChangeFocus(e => { + this._tree.onDidChangeFocus(e => { const [element] = e.elements; if (element && isNonEmptyArray(element.locations)) { @@ -287,9 +287,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { } this.setMetaTitle(localize('meta', " – {0}", names.join(' → '))); } - })); + }, undefined, this._disposables); - this._disposables.add(this._editor.onMouseDown(e => { + this._editor.onMouseDown(e => { const { event, target } = e; if (event.detail !== 2) { return; @@ -304,9 +304,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { options: { selection: target.range! } }); - })); + }, undefined, this._disposables); - this._disposables.add(this._tree.onMouseDblClick(e => { + this._tree.onMouseDblClick(e => { if (e.element && isNonEmptyArray(e.element.locations)) { this.dispose(); this._editorService.openEditor({ @@ -314,9 +314,9 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { options: { selection: e.element.locations[0].range } }); } - })); + }, undefined, this._disposables); - this._disposables.add(this._tree.onDidChangeSelection(e => { + this._tree.onDidChangeSelection(e => { const [element] = e.elements; // don't close on click if (element && isNonEmptyArray(element.locations) && e.browserEvent instanceof KeyboardEvent) { @@ -326,7 +326,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { options: { selection: element.locations[0].range } }); } - })); + }, undefined, this._disposables); } showLoading(): void { @@ -380,7 +380,7 @@ export class CallHierarchyTreePeekWidget extends PeekViewWidget { } }; this._changeDirectionAction = new ChangeHierarchyDirectionAction(this._direction, changeDirection); - this._disposables.add(this._changeDirectionAction); + this._disposables.push(this._changeDirectionAction); this._actionbarWidget.push(this._changeDirectionAction, { icon: true, label: false }); } } diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts index cae81e789b..d460878a29 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleMinimap.ts @@ -32,14 +32,14 @@ export class ToggleMinimapAction extends Action { const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleMinimapAction, ToggleMinimapAction.ID, ToggleMinimapAction.LABEL), 'View: Toggle Minimap'); -/* {{SQL CARBON EDIT}} - Disable unused menu item -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleMinimapAction.ID, - title: nls.localize({ key: 'miShowMinimap', comment: ['&& denotes a mnemonic'] }, "Show &&Minimap"), - toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true) - }, - order: 2 -}); -*/ +// {{SQL CARBON EDIT}} - Disable unused menu item +// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { +// group: '5_editor', +// command: { +// id: ToggleMinimapAction.ID, +// title: nls.localize({ key: 'miToggleMinimap', comment: ['&& denotes a mnemonic'] }, "Toggle &&Minimap"), +// toggled: ContextKeyExpr.equals('config.editor.minimap.enabled', true) +// }, +// order: 2 +// }); +// {{SQL CARBON EDIT}} - End diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts index 7283241db6..87785df7c7 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderControlCharacter.ts @@ -33,14 +33,14 @@ export class ToggleRenderControlCharacterAction extends Action { const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderControlCharacterAction, ToggleRenderControlCharacterAction.ID, ToggleRenderControlCharacterAction.LABEL), 'View: Toggle Control Characters'); -/* {{SQL CARBON EDIT}} - Disable unused menu item -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleRenderControlCharacterAction.ID, - title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Render &&Control Characters"), - toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true) - }, - order: 5 -}); -*/ +// {{SQL CARBON EDIT}} - Disable unused menu item +// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { +// group: '5_editor', +// command: { +// id: ToggleRenderControlCharacterAction.ID, +// title: nls.localize({ key: 'miToggleRenderControlCharacters', comment: ['&& denotes a mnemonic'] }, "Toggle &&Control Characters"), +// toggled: ContextKeyExpr.equals('config.editor.renderControlCharacters', true) +// }, +// order: 4 +// }); +// {{SQL CARBON EDIT}} - End diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts index b182853a2c..5a219f3b4a 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleRenderWhitespace.ts @@ -41,14 +41,14 @@ export class ToggleRenderWhitespaceAction extends Action { const registry = Registry.as(ActionExtensions.WorkbenchActions); registry.registerWorkbenchAction(new SyncActionDescriptor(ToggleRenderWhitespaceAction, ToggleRenderWhitespaceAction.ID, ToggleRenderWhitespaceAction.LABEL), 'View: Toggle Render Whitespace'); -/* {{SQL CARBON EDIT}} - Disable unused menu item -MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { - group: '5_editor', - command: { - id: ToggleRenderWhitespaceAction.ID, - title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "&&Render Whitespace"), - toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none') - }, - order: 4 -}); -*/ +// {{SQL CARBON EDIT}} - Disable unused menu item +// MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { +// group: '5_editor', +// command: { +// id: ToggleRenderWhitespaceAction.ID, +// title: nls.localize({ key: 'miToggleRenderWhitespace', comment: ['&& denotes a mnemonic'] }, "Toggle &&Render Whitespace"), +// toggled: ContextKeyExpr.notEquals('config.editor.renderWhitespace', 'none') +// }, +// order: 3 +// }); +// {{SQL CARBON EDIT}} - End diff --git a/src/vs/workbench/contrib/codeinset/common/codeInset.ts b/src/vs/workbench/contrib/codeinset/common/codeInset.ts new file mode 100644 index 0000000000..3ef92e295d --- /dev/null +++ b/src/vs/workbench/contrib/codeinset/common/codeInset.ts @@ -0,0 +1,70 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ITextModel } from 'vs/editor/common/model'; +import { onUnexpectedExternalError } from 'vs/base/common/errors'; +import { mergeSort } from 'vs/base/common/arrays'; +import { Event } from 'vs/base/common/event'; +import { CancellationToken } from 'vs/base/common/cancellation'; +import { LanguageFeatureRegistry } from 'vs/editor/common/modes/languageFeatureRegistry'; +import { ProviderResult } from 'vs/editor/common/modes'; +import { IRange } from 'vs/editor/common/core/range'; + +export interface ICodeInsetSymbol { + id: string; + range: IRange; + height?: number; +} + +export interface CodeInsetProvider { + onDidChange?: Event; + provideCodeInsets(model: ITextModel, token: CancellationToken): ProviderResult; + resolveCodeInset(model: ITextModel, codeInset: ICodeInsetSymbol, token: CancellationToken): ProviderResult; +} + +export const CodeInsetProviderRegistry = new LanguageFeatureRegistry(); + +export interface ICodeInsetData { + symbol: ICodeInsetSymbol; + provider: CodeInsetProvider; + resolved?: boolean; +} + +export function getCodeInsetData(model: ITextModel, token: CancellationToken): Promise { + + const symbols: ICodeInsetData[] = []; + const providers = CodeInsetProviderRegistry.ordered(model); + + const promises = providers.map(provider => + Promise.resolve(provider.provideCodeInsets(model, token)).then(result => { + if (Array.isArray(result)) { + for (let symbol of result) { + symbols.push({ symbol, provider }); + } + } + }).catch(onUnexpectedExternalError)); + + return Promise.all(promises).then(() => { + + return mergeSort(symbols, (a, b) => { + // sort by lineNumber, provider-rank, and column + if (a.symbol.range.startLineNumber < b.symbol.range.startLineNumber) { + return -1; + } else if (a.symbol.range.startLineNumber > b.symbol.range.startLineNumber) { + return 1; + } else if (providers.indexOf(a.provider) < providers.indexOf(b.provider)) { + return -1; + } else if (providers.indexOf(a.provider) > providers.indexOf(b.provider)) { + return 1; + } else if (a.symbol.range.startColumn < b.symbol.range.startColumn) { + return -1; + } else if (a.symbol.range.startColumn > b.symbol.range.startColumn) { + return 1; + } else { + return 0; + } + }); + }); +} diff --git a/src/vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution.ts b/src/vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution.ts new file mode 100644 index 0000000000..303fd1700e --- /dev/null +++ b/src/vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution.ts @@ -0,0 +1,353 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { CancelablePromise, createCancelablePromise, RunOnceScheduler } from 'vs/base/common/async'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { StableEditorScrollState } from 'vs/editor/browser/core/editorState'; +import * as editorBrowser from 'vs/editor/browser/editorBrowser'; +import * as editorCommon from 'vs/editor/common/editorCommon'; +import { IModelDecorationsChangeAccessor } from 'vs/editor/common/model'; +import { CodeInsetProviderRegistry, getCodeInsetData, ICodeInsetData } from '../common/codeInset'; +import { CodeInsetWidget, CodeInsetHelper } from './codeInsetWidget'; +import { registerEditorContribution } from 'vs/editor/browser/editorExtensions'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; +// import { localize } from 'vs/nls'; + +export class CodeInsetController implements editorCommon.IEditorContribution { + + static get(editor: editorBrowser.ICodeEditor): CodeInsetController { + return editor.getContribution(CodeInsetController.ID); + } + + private static readonly ID: string = 'css.editor.codeInset'; + + private _isEnabled: boolean; + + private _globalToDispose: IDisposable[]; + private _localToDispose: IDisposable[]; + private _insetWidgets: CodeInsetWidget[]; + private _pendingWebviews = new Map any>(); + private _currentFindCodeInsetSymbolsPromise: CancelablePromise | null; + private _modelChangeCounter: number; + private _currentResolveCodeInsetSymbolsPromise: CancelablePromise | null; + private _detectVisibleInsets: RunOnceScheduler; + + constructor( + private _editor: editorBrowser.ICodeEditor, + @IConfigurationService private readonly _configService: IConfigurationService, + ) { + this._isEnabled = this._configService.getValue('editor.codeInsets'); + + this._globalToDispose = []; + this._localToDispose = []; + this._insetWidgets = []; + this._currentFindCodeInsetSymbolsPromise = null; + this._modelChangeCounter = 0; + + this._globalToDispose.push(this._editor.onDidChangeModel(() => this._onModelChange())); + this._globalToDispose.push(this._editor.onDidChangeModelLanguage(() => this._onModelChange())); + this._globalToDispose.push(this._configService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.codeInsets')) { + let prevIsEnabled = this._isEnabled; + this._isEnabled = this._configService.getValue('editor.codeInsets'); + if (prevIsEnabled !== this._isEnabled) { + this._onModelChange(); + } + } + })); + this._globalToDispose.push(CodeInsetProviderRegistry.onDidChange(this._onModelChange, this)); + this._onModelChange(); + } + + dispose(): void { + this._localDispose(); + this._globalToDispose = dispose(this._globalToDispose); + } + + acceptWebview(symbolId: string, webviewElement: WebviewElement): boolean { + const pendingWebview = this._pendingWebviews.get(symbolId); + if (pendingWebview) { + pendingWebview(webviewElement); + this._pendingWebviews.delete(symbolId); + return true; + } + return false; + } + + private _localDispose(): void { + if (this._currentFindCodeInsetSymbolsPromise) { + this._currentFindCodeInsetSymbolsPromise.cancel(); + this._currentFindCodeInsetSymbolsPromise = null; + this._modelChangeCounter++; + } + if (this._currentResolveCodeInsetSymbolsPromise) { + this._currentResolveCodeInsetSymbolsPromise.cancel(); + this._currentResolveCodeInsetSymbolsPromise = null; + } + this._localToDispose = dispose(this._localToDispose); + } + + getId(): string { + return CodeInsetController.ID; + } + + private _onModelChange(): void { + this._localDispose(); + + const model = this._editor.getModel(); + if (!model || !this._isEnabled || !CodeInsetProviderRegistry.has(model)) { + return; + } + + for (const provider of CodeInsetProviderRegistry.all(model)) { + if (typeof provider.onDidChange === 'function') { + let registration = provider.onDidChange(() => scheduler.schedule()); + this._localToDispose.push(registration); + } + } + + this._detectVisibleInsets = new RunOnceScheduler(() => { + this._onViewportChanged(); + }, 500); + + const scheduler = new RunOnceScheduler(() => { + const counterValue = ++this._modelChangeCounter; + if (this._currentFindCodeInsetSymbolsPromise) { + this._currentFindCodeInsetSymbolsPromise.cancel(); + } + + this._currentFindCodeInsetSymbolsPromise = createCancelablePromise(token => getCodeInsetData(model, token)); + + this._currentFindCodeInsetSymbolsPromise.then(codeInsetData => { + if (counterValue === this._modelChangeCounter) { // only the last one wins + this._renderCodeInsetSymbols(codeInsetData); + this._detectVisibleInsets.schedule(); + } + }, onUnexpectedError); + }, 250); + + this._localToDispose.push(scheduler); + + this._localToDispose.push(this._detectVisibleInsets); + + this._localToDispose.push(this._editor.onDidChangeModelContent(() => { + this._editor.changeDecorations(changeAccessor => { + this._editor.changeViewZones(viewAccessor => { + let toDispose: CodeInsetWidget[] = []; + let lastInsetLineNumber: number = -1; + this._insetWidgets.forEach(inset => { + if (!inset.isValid() || lastInsetLineNumber === inset.getLineNumber()) { + // invalid -> Inset collapsed, attach range doesn't exist anymore + // line_number -> insets should never be on the same line + toDispose.push(inset); + } + else { + inset.reposition(viewAccessor); + lastInsetLineNumber = inset.getLineNumber(); + } + }); + let helper = new CodeInsetHelper(); + toDispose.forEach((l) => { + l.dispose(helper, viewAccessor); + this._insetWidgets.splice(this._insetWidgets.indexOf(l), 1); + }); + helper.commit(changeAccessor); + }); + }); + // Compute new `visible` code insets + this._detectVisibleInsets.schedule(); + // Ask for all references again + scheduler.schedule(); + })); + + this._localToDispose.push(this._editor.onDidScrollChange(e => { + if (e.scrollTopChanged && this._insetWidgets.length > 0) { + this._detectVisibleInsets.schedule(); + } + })); + + this._localToDispose.push(this._editor.onDidLayoutChange(() => { + this._detectVisibleInsets.schedule(); + })); + + this._localToDispose.push(toDisposable(() => { + if (this._editor.getModel()) { + const scrollState = StableEditorScrollState.capture(this._editor); + this._editor.changeDecorations((changeAccessor) => { + this._editor.changeViewZones((accessor) => { + this._disposeAllInsets(changeAccessor, accessor); + }); + }); + scrollState.restore(this._editor); + } else { + // No accessors available + this._disposeAllInsets(null, null); + } + })); + + scheduler.schedule(); + } + + private _disposeAllInsets(decChangeAccessor: IModelDecorationsChangeAccessor | null, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor | null): void { + let helper = new CodeInsetHelper(); + this._insetWidgets.forEach((Inset) => Inset.dispose(helper, viewZoneChangeAccessor)); + if (decChangeAccessor) { + helper.commit(decChangeAccessor); + } + this._insetWidgets = []; + } + + private _renderCodeInsetSymbols(symbols: ICodeInsetData[]): void { + if (!this._editor.hasModel()) { + return; + } + + let maxLineNumber = this._editor.getModel().getLineCount(); + let groups: ICodeInsetData[][] = []; + let lastGroup: ICodeInsetData[] | undefined; + + for (let symbol of symbols) { + let line = symbol.symbol.range.startLineNumber; + if (line < 1 || line > maxLineNumber) { + // invalid code Inset + continue; + } else if (lastGroup && lastGroup[lastGroup.length - 1].symbol.range.startLineNumber === line) { + // on same line as previous + lastGroup.push(symbol); + } else { + // on later line as previous + lastGroup = [symbol]; + groups.push(lastGroup); + } + } + + const scrollState = StableEditorScrollState.capture(this._editor); + + this._editor.changeDecorations(changeAccessor => { + this._editor.changeViewZones(accessor => { + + let codeInsetIndex = 0, groupsIndex = 0, helper = new CodeInsetHelper(); + + while (groupsIndex < groups.length && codeInsetIndex < this._insetWidgets.length) { + + let symbolsLineNumber = groups[groupsIndex][0].symbol.range.startLineNumber; + let codeInsetLineNumber = this._insetWidgets[codeInsetIndex].getLineNumber(); + + if (codeInsetLineNumber < symbolsLineNumber) { + this._insetWidgets[codeInsetIndex].dispose(helper, accessor); + this._insetWidgets.splice(codeInsetIndex, 1); + } else if (codeInsetLineNumber === symbolsLineNumber) { + this._insetWidgets[codeInsetIndex].updateCodeInsetSymbols(groups[groupsIndex], helper); + groupsIndex++; + codeInsetIndex++; + } else { + this._insetWidgets.splice( + codeInsetIndex, + 0, + new CodeInsetWidget(groups[groupsIndex], this._editor, helper) + ); + codeInsetIndex++; + groupsIndex++; + } + } + + // Delete extra code insets + while (codeInsetIndex < this._insetWidgets.length) { + this._insetWidgets[codeInsetIndex].dispose(helper, accessor); + this._insetWidgets.splice(codeInsetIndex, 1); + } + + // Create extra symbols + while (groupsIndex < groups.length) { + this._insetWidgets.push(new CodeInsetWidget( + groups[groupsIndex], + this._editor, helper + )); + groupsIndex++; + } + + helper.commit(changeAccessor); + }); + }); + + scrollState.restore(this._editor); + } + + private _onViewportChanged(): void { + if (this._currentResolveCodeInsetSymbolsPromise) { + this._currentResolveCodeInsetSymbolsPromise.cancel(); + this._currentResolveCodeInsetSymbolsPromise = null; + } + + const model = this._editor.getModel(); + if (!model) { + return; + } + + const allWidgetRequests: ICodeInsetData[][] = []; + const insetWidgets: CodeInsetWidget[] = []; + this._insetWidgets.forEach(inset => { + const widgetRequests = inset.computeIfNecessary(model); + if (widgetRequests) { + allWidgetRequests.push(widgetRequests); + insetWidgets.push(inset); + } + }); + + if (allWidgetRequests.length === 0) { + return; + } + + this._currentResolveCodeInsetSymbolsPromise = createCancelablePromise(token => { + + const allPromises = allWidgetRequests.map((widgetRequests, r) => { + + const widgetPromises = widgetRequests.map(request => { + if (request.resolved) { + return Promise.resolve(undefined); + } + let a = new Promise(resolve => { + this._pendingWebviews.set(request.symbol.id, element => { + request.resolved = true; + insetWidgets[r].adoptWebview(element); + resolve(); + }); + }); + let b = request.provider.resolveCodeInset(model, request.symbol, token); + return Promise.all([a, b]); + }); + + return Promise.all(widgetPromises); + }); + + return Promise.all(allPromises); + }); + + this._currentResolveCodeInsetSymbolsPromise.then(() => { + this._currentResolveCodeInsetSymbolsPromise = null; + }).catch(err => { + this._currentResolveCodeInsetSymbolsPromise = null; + onUnexpectedError(err); + }); + } +} + +registerEditorContribution(CodeInsetController); + + +Registry.as(ConfigurationExtensions.Configuration).registerConfiguration({ + id: 'editor', + properties: { + // ['editor.codeInsets']: { + // description: localize('editor.codeInsets', "Enable/disable editor code insets"), + // type: 'boolean', + // default: false + // } + } +}); diff --git a/src/typings/vscode-windows-ca-certs.d.ts b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css similarity index 88% rename from src/typings/vscode-windows-ca-certs.d.ts rename to src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css index 37b2282827..06e13f322f 100644 --- a/src/typings/vscode-windows-ca-certs.d.ts +++ b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.css @@ -3,4 +3,6 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -declare module 'vscode-windows-ca-certs'; +.monaco-editor .code-inset { + z-index: 10; +} diff --git a/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts new file mode 100644 index 0000000000..d7acdaf730 --- /dev/null +++ b/src/vs/workbench/contrib/codeinset/electron-browser/codeInsetWidget.ts @@ -0,0 +1,193 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./codeInsetWidget'; +import { Range } from 'vs/editor/common/core/range'; +import * as editorBrowser from 'vs/editor/browser/editorBrowser'; +import { ICodeInsetData } from '../common/codeInset'; +import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; +import { IModelDeltaDecoration, IModelDecorationsChangeAccessor, ITextModel } from 'vs/editor/common/model'; +import { WebviewElement } from 'vs/workbench/contrib/webview/electron-browser/webviewElement'; + + +export interface IDecorationIdCallback { + (decorationId: string): void; +} + +export class CodeInsetHelper { + + private _removeDecorations: string[]; + private _addDecorations: IModelDeltaDecoration[]; + private _addDecorationsCallbacks: IDecorationIdCallback[]; + + constructor() { + this._removeDecorations = []; + this._addDecorations = []; + this._addDecorationsCallbacks = []; + } + + addDecoration(decoration: IModelDeltaDecoration, callback: IDecorationIdCallback): void { + this._addDecorations.push(decoration); + this._addDecorationsCallbacks.push(callback); + } + + removeDecoration(decorationId: string): void { + this._removeDecorations.push(decorationId); + } + + commit(changeAccessor: IModelDecorationsChangeAccessor): void { + let resultingDecorations = changeAccessor.deltaDecorations(this._removeDecorations, this._addDecorations); + for (let i = 0, len = resultingDecorations.length; i < len; i++) { + this._addDecorationsCallbacks[i](resultingDecorations[i]); + } + } +} + +export class CodeInsetWidget { + + private readonly _editor: editorBrowser.ICodeEditor; + private _webview: WebviewElement; + private _viewZone: editorBrowser.IViewZone; + private _viewZoneId?: number = undefined; + private _decorationIds: string[]; + private _data: ICodeInsetData[]; + private _range: Range; + + constructor( + data: ICodeInsetData[], // all the insets on the same line (often just one) + editor: editorBrowser.ICodeEditor, + helper: CodeInsetHelper + ) { + this._editor = editor; + this._data = data; + this._decorationIds = new Array(this._data.length); + + this._data.forEach((codeInsetData, i) => { + + helper.addDecoration({ + range: codeInsetData.symbol.range, + options: ModelDecorationOptions.EMPTY + }, id => this._decorationIds[i] = id); + + // the range contains all insets on this line + if (!this._range) { + this._range = Range.lift(codeInsetData.symbol.range); + } else { + this._range = Range.plusRange(this._range, codeInsetData.symbol.range); + } + }); + } + + public dispose(helper: CodeInsetHelper, viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor | null): void { + while (this._decorationIds.length) { + const decoration = this._decorationIds.pop(); + if (decoration) { + helper.removeDecoration(decoration); + } + } + if (viewZoneChangeAccessor) { + if (typeof this._viewZoneId !== 'undefined') { + viewZoneChangeAccessor.removeZone(this._viewZoneId); + } + this._viewZone = undefined!; + } + if (this._webview) { + this._webview.dispose(); + } + } + + public isValid(): boolean { + return this._editor.hasModel() && this._decorationIds.some((id, i) => { + const range = this._editor.getModel()!.getDecorationRange(id); + const symbol = this._data[i].symbol; + return !!range && Range.isEmpty(symbol.range) === range.isEmpty(); + }); + } + + public updateCodeInsetSymbols(data: ICodeInsetData[], helper: CodeInsetHelper): void { + while (this._decorationIds.length) { + const decoration = this._decorationIds.pop(); + if (decoration) { + helper.removeDecoration(decoration); + } + } + this._data = data; + this._decorationIds = new Array(this._data.length); + this._data.forEach((codeInsetData, i) => { + helper.addDecoration({ + range: codeInsetData.symbol.range, + options: ModelDecorationOptions.EMPTY + }, id => this._decorationIds[i] = id); + }); + } + + public computeIfNecessary(model: ITextModel): ICodeInsetData[] { + // Read editor current state + for (let i = 0; i < this._decorationIds.length; i++) { + const range = model.getDecorationRange(this._decorationIds[i]); + if (range) { + this._data[i].symbol.range = range; + } + } + return this._data; + } + + public getLineNumber(): number { + if (this._editor.hasModel()) { + const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]); + if (range) { + return range.startLineNumber; + } + } + return -1; + } + + public adoptWebview(webview: WebviewElement): void { + + const lineNumber = this._range.endLineNumber; + this._editor.changeViewZones(accessor => { + + if (this._viewZoneId) { + accessor.removeZone(this._viewZoneId); + this._webview.dispose(); + } + + const div = document.createElement('div'); + div.className = 'code-inset'; + webview.mountTo(div); + webview.onMessage((e: { type: string, payload: any }) => { + // The webview contents can use a "size-info" message to report its size. + if (e && e.type === 'size-info') { + const margin = e.payload.height > 0 ? 5 : 0; + this._viewZone.heightInPx = e.payload.height + margin; + this._editor.changeViewZones(accessor => { + if (this._viewZoneId) { + accessor.layoutZone(this._viewZoneId); + } + }); + } + }); + this._viewZone = { + afterLineNumber: lineNumber, + heightInPx: 50, + domNode: div + }; + this._viewZoneId = accessor.addZone(this._viewZone); + this._webview = webview; + }); + } + + public reposition(viewZoneChangeAccessor: editorBrowser.IViewZoneChangeAccessor): void { + if (this.isValid() && this._editor.hasModel()) { + const range = this._editor.getModel().getDecorationRange(this._decorationIds[0]); + if (range) { + this._viewZone.afterLineNumber = range.endLineNumber; + } + if (this._viewZoneId) { + viewZoneChangeAccessor.layoutZone(this._viewZoneId); + } + } + } +} diff --git a/src/vs/workbench/contrib/comments/browser/commentFormActions.ts b/src/vs/workbench/contrib/comments/browser/commentFormActions.ts index ef737c498a..28d508fe79 100644 --- a/src/vs/workbench/contrib/comments/browser/commentFormActions.ts +++ b/src/vs/workbench/contrib/comments/browser/commentFormActions.ts @@ -6,57 +6,41 @@ import * as DOM from 'vs/base/browser/dom'; import { Button } from 'vs/base/browser/ui/button/button'; import { IAction } from 'vs/base/common/actions'; -import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, dispose } from 'vs/base/common/lifecycle'; import { IMenu } from 'vs/platform/actions/common/actions'; import { attachButtonStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; -export class CommentFormActions implements IDisposable { +export class CommentFormActions extends Disposable { private _buttonElements: HTMLElement[] = []; - private readonly _toDispose = new DisposableStore(); - private _actions: IAction[]; constructor( private container: HTMLElement, private actionHandler: (action: IAction) => void, private themeService: IThemeService - ) { } + ) { + super(); + } setActions(menu: IMenu) { - this._toDispose.clear(); - + dispose(this._toDispose); this._buttonElements.forEach(b => DOM.removeNode(b)); const groups = menu.getActions({ shouldForwardArgs: true }); for (const group of groups) { const [, actions] = group; - this._actions = actions; actions.forEach(action => { const button = new Button(this.container); this._buttonElements.push(button.element); - this._toDispose.add(button); - this._toDispose.add(attachButtonStyler(button, this.themeService)); - this._toDispose.add(button.onDidClick(() => this.actionHandler(action))); + this._toDispose.push(button); + this._toDispose.push(attachButtonStyler(button, this.themeService)); + this._toDispose.push(button.onDidClick(() => this.actionHandler(action))); button.enabled = action.enabled; button.label = action.label; }); } } - - triggerDefaultAction() { - if (this._actions.length) { - let lastAction = this._actions[0]; - - if (lastAction.enabled) { - this.actionHandler(lastAction); - } - } - } - - dispose() { - this._toDispose.dispose(); - } } \ No newline at end of file diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 98b720ad1b..bd686dd3cb 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -178,8 +178,8 @@ export class CommentNode extends Disposable { let commentMenus = this.commentService.getCommentMenus(this.owner); const menu = commentMenus.getCommentTitleActions(this.comment, this._contextKeyService); - this._register(menu); - this._register(menu.onDidChange(e => { + this._toDispose.push(menu); + this._toDispose.push(menu.onDidChange(e => { const contributedActions = menu.getActions({ shouldForwardArgs: true }).reduce((r, [, actions]) => [...r, ...actions], []); this.toolbar.setActions(contributedActions); })); @@ -217,7 +217,7 @@ export class CommentNode extends Disposable { this.registerActionBarListeners(this._actionsToolbarContainer); this.toolbar.setActions(actions, [])(); - this._register(this.toolbar); + this._toDispose.push(this.toolbar); } } @@ -354,7 +354,7 @@ export class CommentNode extends Disposable { return this.actionViewItemProvider(action as Action); } }); - this._register(this._reactionsActionBar); + this._toDispose.push(this._reactionsActionBar); this.comment.commentReactions!.map(reaction => { let action = new ReactionAction(`reaction.${reaction.label}`, `${reaction.label}`, reaction.hasReacted && reaction.canEdit ? 'active' : '', reaction.canEdit, async () => { @@ -424,14 +424,12 @@ export class CommentNode extends Disposable { uri: this._commentEditor.getModel()!.uri, value: this.comment.body.value }; - this.commentService.setActiveCommentThread(commentThread); this._commentEditorDisposables.push(this._commentEditor.onDidFocusEditorWidget(() => { commentThread.input = { uri: this._commentEditor!.getModel()!.uri, value: this.comment.body.value }; - this.commentService.setActiveCommentThread(commentThread); })); this._commentEditorDisposables.push(this._commentEditor.onDidChangeModelContent(e => { @@ -441,14 +439,13 @@ export class CommentNode extends Disposable { let input = commentThread.input; input.value = newVal; commentThread.input = input; - this.commentService.setActiveCommentThread(commentThread); } } })); } - this._register(this._commentEditor); - this._register(this._commentEditorModel); + this._toDispose.push(this._commentEditor); + this._toDispose.push(this._commentEditorModel); } private removeCommentEditor() { @@ -489,7 +486,6 @@ export class CommentNode extends Disposable { uri: this._commentEditor.getModel()!.uri, value: newBody }; - this.commentService.setActiveCommentThread(commentThread); let commandId = this.comment.editCommand.id; let args = this.comment.editCommand.arguments || []; @@ -527,7 +523,6 @@ export class CommentNode extends Disposable { if (result.confirmed) { try { if (this.comment.deleteCommand) { - this.commentService.setActiveCommentThread(this.commentThread); let commandId = this.comment.deleteCommand.id; let args = this.comment.deleteCommand.arguments || []; @@ -566,8 +561,8 @@ export class CommentNode extends Disposable { const menus = this.commentService.getCommentMenus(this.owner); const menu = menus.getCommentActions(this.comment, this._contextKeyService); - this._register(menu); - this._register(menu.onDidChange(() => { + this._toDispose.push(menu); + this._toDispose.push(menu.onDidChange(() => { this._commentFormActions.setActions(menu); })); @@ -604,17 +599,17 @@ export class CommentNode extends Disposable { const cancelEditButton = new Button(formActions); cancelEditButton.label = nls.localize('label.cancel', "Cancel"); - this._register(attachButtonStyler(cancelEditButton, this.themeService)); + this._toDispose.push(attachButtonStyler(cancelEditButton, this.themeService)); - this._register(cancelEditButton.onDidClick(_ => { + this._toDispose.push(cancelEditButton.onDidClick(_ => { this.removeCommentEditor(); })); this._updateCommentButton = new Button(formActions); this._updateCommentButton.label = UPDATE_COMMENT_LABEL; - this._register(attachButtonStyler(this._updateCommentButton, this.themeService)); + this._toDispose.push(attachButtonStyler(this._updateCommentButton, this.themeService)); - this._register(this._updateCommentButton.onDidClick(_ => { + this._toDispose.push(this._updateCommentButton.onDidClick(_ => { this.editComment(); })); @@ -627,21 +622,21 @@ export class CommentNode extends Disposable { } private registerActionBarListeners(actionsContainer: HTMLElement): void { - this._register(dom.addDisposableListener(this._domNode, 'mouseenter', () => { + this._toDispose.push(dom.addDisposableListener(this._domNode, 'mouseenter', () => { actionsContainer.classList.remove('hidden'); })); - this._register(dom.addDisposableListener(this._domNode, 'focus', () => { + this._toDispose.push(dom.addDisposableListener(this._domNode, 'focus', () => { actionsContainer.classList.remove('hidden'); })); - this._register(dom.addDisposableListener(this._domNode, 'mouseleave', () => { + this._toDispose.push(dom.addDisposableListener(this._domNode, 'mouseleave', () => { if (!this._domNode.contains(document.activeElement)) { actionsContainer.classList.add('hidden'); } })); - this._register(dom.addDisposableListener(this._domNode, 'focusout', (e: FocusEvent) => { + this._toDispose.push(dom.addDisposableListener(this._domNode, 'focusout', (e: FocusEvent) => { if (!this._domNode.contains((e.relatedTarget))) { actionsContainer.classList.add('hidden'); @@ -714,4 +709,8 @@ export class CommentNode extends Disposable { }, 3000); } } + + dispose() { + this._toDispose.forEach(disposeable => disposeable.dispose()); + } } diff --git a/src/vs/workbench/contrib/comments/browser/commentService.ts b/src/vs/workbench/contrib/comments/browser/commentService.ts index af60032068..52b3f2fe7c 100644 --- a/src/vs/workbench/contrib/comments/browser/commentService.ts +++ b/src/vs/workbench/contrib/comments/browser/commentService.ts @@ -38,7 +38,6 @@ export interface ICommentService { readonly onDidSetResourceCommentInfos: Event; readonly onDidSetAllCommentThreads: Event; readonly onDidUpdateCommentThreads: Event; - readonly onDidChangeActiveCommentThread: Event; readonly onDidChangeActiveCommentingRange: Event<{ range: Range, commentingRangesInfo: CommentingRanges }>; readonly onDidSetDataProvider: Event; readonly onDidDeleteDataProvider: Event; @@ -49,7 +48,6 @@ export interface ICommentService { unregisterCommentController(owner: string): void; getCommentController(owner: string): MainThreadCommentController | undefined; createCommentThreadTemplate(owner: string, resource: URI, range: Range): void; - updateCommentThreadTemplate(owner: string, threadHandle: number, range: Range): Promise; getCommentMenus(owner: string): CommentMenus; registerDataProvider(owner: string, commentProvider: DocumentCommentProvider): void; unregisterDataProvider(owner: string): void; @@ -71,7 +69,6 @@ export interface ICommentService { deleteReaction(owner: string, resource: URI, comment: Comment, reaction: CommentReaction): Promise; getReactionGroup(owner: string): CommentReaction[] | undefined; toggleReaction(owner: string, resource: URI, thread: CommentThread2, comment: Comment, reaction: CommentReaction): Promise; - setActiveCommentThread(commentThread: CommentThread | null): void; } export class CommentService extends Disposable implements ICommentService { @@ -92,9 +89,6 @@ export class CommentService extends Disposable implements ICommentService { private readonly _onDidUpdateCommentThreads: Emitter = this._register(new Emitter()); readonly onDidUpdateCommentThreads: Event = this._onDidUpdateCommentThreads.event; - private readonly _onDidChangeActiveCommentThread = this._register(new Emitter()); - readonly onDidChangeActiveCommentThread = this._onDidChangeActiveCommentThread.event; - private readonly _onDidChangeActiveCommentingRange: Emitter<{ range: Range, commentingRangesInfo: CommentingRanges @@ -115,10 +109,6 @@ export class CommentService extends Disposable implements ICommentService { super(); } - setActiveCommentThread(commentThread: CommentThread | null) { - this._onDidChangeActiveCommentThread.fire(commentThread); - } - setDocumentComments(resource: URI, commentInfos: ICommentInfo[]): void { this._onDidSetResourceCommentInfos.fire({ resource, commentInfos }); } @@ -155,16 +145,6 @@ export class CommentService extends Disposable implements ICommentService { commentController.createCommentThreadTemplate(resource, range); } - async updateCommentThreadTemplate(owner: string, threadHandle: number, range: Range) { - const commentController = this._commentControls.get(owner); - - if (!commentController) { - return; - } - - await commentController.updateCommentThreadTemplate(threadHandle, range); - } - disposeCommentThread(owner: string, threadId: string) { let controller = this.getCommentController(owner); if (controller) { diff --git a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts index e813687dc7..0a205c1027 100644 --- a/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts +++ b/src/vs/workbench/contrib/comments/browser/commentThreadWidget.ts @@ -211,10 +211,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this._bodyElement = dom.$('.body'); container.appendChild(this._bodyElement); - - dom.addDisposableListener(this._bodyElement, dom.EventType.FOCUS_IN, e => { - this.commentService.setActiveCommentThread(this._commentThread); - }); } protected _fillHead(container: HTMLElement): void { @@ -236,7 +232,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } }); - this._disposables.add(this._actionbarWidget); + this._disposables.push(this._actionbarWidget); this._collapseAction = new Action('review.expand', nls.localize('label.collapse', "Collapse"), COLLAPSE_ACTION_CLASS, true, () => this.collapse()); @@ -244,8 +240,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const menu = this._commentMenus.getCommentThreadTitleActions(this._commentThread as modes.CommentThread2, this._contextKeyService); this.setActionBarActions(menu); - this._disposables.add(menu); - this._disposables.add(menu.onDidChange(e => { + this._disposables.push(menu); + this._disposables.push(menu.onDidChange(e => { this.setActionBarActions(menu); })); } else { @@ -269,7 +265,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } else { const deleteCommand = (this._commentThread as modes.CommentThread2).deleteCommand; if (deleteCommand) { - this.commentService.setActiveCommentThread(this._commentThread); return this.commandService.executeCommand(deleteCommand.id, ...(deleteCommand.arguments || [])); } else if (this._commentEditor.getValue() === '') { this.commentService.disposeCommentThread(this._owner, this._commentThread.threadId!); @@ -420,8 +415,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget display(lineNumber: number) { this._commentGlyph = new CommentGlyphWidget(this.editor, lineNumber); - this._disposables.add(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); - this._disposables.add(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); + this._disposables.push(this.editor.onMouseDown(e => this.onEditorMouseDown(e))); + this._disposables.push(this.editor.onMouseUp(e => this.onEditorMouseUp(e))); let headHeight = Math.ceil(this.editor.getConfiguration().lineHeight * 1.2); this._headElement.style.height = `${headHeight}px`; @@ -459,10 +454,10 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } const model = this.modelService.createModel(this._pendingComment || '', this.modeService.createByFilepathOrFirstLine(resource.path), resource, false); - this._disposables.add(model); + this._disposables.push(model); this._commentEditor.setModel(model); - this._disposables.add(this._commentEditor); - this._disposables.add(this._commentEditor.getModel()!.onDidChangeContent(() => { + this._disposables.push(this._commentEditor); + this._disposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => { this.setCommentEditorDecorations(); this._commentEditorIsEmpty.set(!this._commentEditor.getValue()); })); @@ -521,7 +516,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget uri: this._commentEditor.getModel()!.uri, value: this._commentEditor.getValue() }; - this.commentService.setActiveCommentThread(this._commentThread); })); this._commentThreadDisposables.push(this._commentEditor.getModel()!.onDidChangeContent(() => { @@ -532,7 +526,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget newInput.value = modelContent; thread.input = newInput; } - this.commentService.setActiveCommentThread(this._commentThread); })); this._commentThreadDisposables.push((this._commentThread as modes.CommentThread2).onDidChangeInput(input => { @@ -658,7 +651,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget deletedraftButton.label = deleteDraftLabel; deletedraftButton.enabled = true; - this._disposables.add(deletedraftButton.onDidClick(async () => { + this._disposables.push(deletedraftButton.onDidClick(async () => { try { await this.commentService.deleteDraft(this._owner, this.editor.getModel()!.uri); } catch (e) { @@ -691,7 +684,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const startDraftLabel = this.commentService.getStartDraftLabel(this._owner); if (startDraftLabel) { const draftButton = new Button(container); - this._disposables.add(attachButtonStyler(draftButton, this.themeService)); + this._disposables.push(attachButtonStyler(draftButton, this.themeService)); draftButton.label = this.commentService.getStartDraftLabel(this._owner)!; draftButton.enabled = model.getValueLength() > 0; @@ -703,7 +696,7 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } })); - this._disposables.add(draftButton.onDidClick(async () => { + this._disposables.push(draftButton.onDidClick(async () => { try { await this.commentService.startDraft(this._owner, this.editor.getModel()!.uri); await this.createComment(); @@ -726,20 +719,19 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if (acceptInputCommand) { const button = new Button(container); - this._disposables.add(attachButtonStyler(button, this.themeService)); + this._disposables.push(attachButtonStyler(button, this.themeService)); button.label = acceptInputCommand.title; - this._disposables.add(button.onDidClick(async () => { + this._disposables.push(button.onDidClick(async () => { commentThread.input = { uri: this._commentEditor.getModel()!.uri, value: this._commentEditor.getValue() }; - this.commentService.setActiveCommentThread(this._commentThread); await this.commandService.executeCommand(acceptInputCommand.id, ...(acceptInputCommand.arguments || [])); })); button.enabled = model.getValueLength() > 0; - this._disposables.add(this._commentEditor.onDidChangeModelContent(_ => { + this._disposables.push(this._commentEditor.onDidChangeModelContent(_ => { if (this._commentEditor.getValue()) { button.enabled = true; } else { @@ -751,15 +743,14 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget if (additionalCommands) { additionalCommands.reverse().forEach(command => { const button = new Button(container); - this._disposables.add(attachButtonStyler(button, this.themeService)); + this._disposables.push(attachButtonStyler(button, this.themeService)); button.label = command.title; - this._disposables.add(button.onDidClick(async () => { + this._disposables.push(button.onDidClick(async () => { commentThread.input = { uri: this._commentEditor.getModel()!.uri, value: this._commentEditor.getValue() }; - this.commentService.setActiveCommentThread(this._commentThread); await this.commandService.executeCommand(command.id, ...(command.arguments || [])); })); }); @@ -767,19 +758,12 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const menu = this._commentMenus.getCommentThreadActions(commentThread, this._contextKeyService); - this._disposables.add(menu); - this._disposables.add(menu.onDidChange(() => { + this._disposables.push(menu); + this._disposables.push(menu.onDidChange(() => { this._commentFormActions.setActions(menu); })); - this._commentFormActions = new CommentFormActions(container, async (action: IAction) => { - if (!commentThread.comments || !commentThread.comments.length) { - let newPosition = this.getPosition(); - - if (newPosition) { - this.commentService.updateCommentThreadTemplate(this.owner, commentThread.commentThreadHandle, new Range(newPosition.lineNumber, 1, newPosition.lineNumber, 1)); - } - } + this._commentFormActions = new CommentFormActions(container, (action: IAction) => { action.run({ thread: this._commentThread, text: this._commentEditor.getValue(), @@ -802,8 +786,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget this, this._markdownRenderer); - this._disposables.add(newCommentNode); - this._disposables.add(newCommentNode.onDidDelete(deletedNode => { + this._disposables.push(newCommentNode); + this._disposables.push(newCommentNode.onDidDelete(deletedNode => { const deletedNodeId = deletedNode.comment.commentId; const deletedElementIndex = arrays.firstIndex(this._commentElements, commentNode => commentNode.comment.commentId === deletedNodeId); if (deletedElementIndex > -1) { @@ -837,14 +821,11 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget uri: this._commentEditor.getModel()!.uri, value: this._commentEditor.getValue() }; - this.commentService.setActiveCommentThread(this._commentThread); let commandId = commentThread.acceptInputCommand.id; let args = commentThread.acceptInputCommand.arguments || []; await this.commandService.executeCommand(commandId, ...args); return; - } else if (this._commentFormActions) { - this._commentFormActions.triggerDefaultAction(); } } else { this.createComment(); @@ -963,8 +944,8 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget } this._reviewThreadReplyButton.textContent = nls.localize('reply', "Reply..."); // bind click/escape actions for reviewThreadReplyButton and textArea - this._disposables.add(dom.addDisposableListener(this._reviewThreadReplyButton, 'click', _ => this.expandReplyArea())); - this._disposables.add(dom.addDisposableListener(this._reviewThreadReplyButton, 'focus', _ => this.expandReplyArea())); + this._disposables.push(dom.addDisposableListener(this._reviewThreadReplyButton, 'click', _ => this.expandReplyArea())); + this._disposables.push(dom.addDisposableListener(this._reviewThreadReplyButton, 'focus', _ => this.expandReplyArea())); this._commentEditor.onDidBlurEditorWidget(() => { if (this._commentEditor.getModel()!.getValueLength() === 0 && dom.hasClass(this._commentForm, 'expand')) { @@ -982,13 +963,6 @@ export class ReviewZoneWidget extends ZoneWidget implements ICommentThreadWidget const frameThickness = Math.round(lineHeight / 9) * 2; const computedLinesNumber = Math.ceil((headHeight + dimensions.height + arrowHeight + frameThickness + 8 /** margin bottom to avoid margin collapse */) / lineHeight); - - let currentPosition = this.getPosition(); - - if (this._viewZone && currentPosition && currentPosition.lineNumber !== this._viewZone.afterLineNumber) { - this._viewZone.afterLineNumber = currentPosition.lineNumber; - } - this._relayout(computedLinesNumber); } } diff --git a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts index ee5db0c323..81797bda5f 100644 --- a/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts +++ b/src/vs/workbench/contrib/comments/browser/commentsTreeViewer.ts @@ -7,7 +7,7 @@ import * as dom from 'vs/base/browser/dom'; import * as nls from 'vs/nls'; import { renderMarkdown } from 'vs/base/browser/htmlContentRenderer'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IDataSource, IFilter, IRenderer as ITreeRenderer, ITree } from 'vs/base/parts/tree/browser/tree'; import { IOpenerService } from 'vs/platform/opener/common/opener'; @@ -62,7 +62,7 @@ interface ICommentThreadTemplateData { icon: HTMLImageElement; userName: HTMLSpanElement; commentText: HTMLElement; - disposables: IDisposable[]; + disposables: Disposable[]; } export class CommentsModelRenderer implements ITreeRenderer { diff --git a/src/vs/workbench/contrib/comments/browser/media/review.css b/src/vs/workbench/contrib/comments/browser/media/review.css index 053cbc7f4f..f6e500ff2e 100644 --- a/src/vs/workbench/contrib/comments/browser/media/review.css +++ b/src/vs/workbench/contrib/comments/browser/media/review.css @@ -178,7 +178,6 @@ .monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions { display: none; background-image: url(./reaction.svg); - background-size: 24px; width: 26px; height: 16px; background-repeat: no-repeat; @@ -189,7 +188,6 @@ .monaco-editor .review-widget .body .review-comment .review-comment-contents .comment-reactions:hover .action-item a.action-label.toolbar-toggle-pickReactions { display: inline-block; - background-size: 24px; } .monaco-editor.vs-dark .review-widget .body .review-comment .review-comment-contents .comment-reactions .action-item a.action-label.toolbar-toggle-pickReactions { @@ -214,7 +212,7 @@ background-image: url(./reaction.svg); width: 18px; height: 18px; - background-size: 24px; + background-size: 100% auto; background-position: center; background-repeat: no-repeat; } diff --git a/src/vs/workbench/contrib/comments/common/commentModel.ts b/src/vs/workbench/contrib/comments/common/commentModel.ts index 2716606952..ca770a151b 100644 --- a/src/vs/workbench/contrib/comments/common/commentModel.ts +++ b/src/vs/workbench/contrib/comments/common/commentModel.ts @@ -98,7 +98,7 @@ export class CommentsModel { const index = firstIndex(matchingResourceData.commentThreads, (commentThread) => commentThread.threadId === thread.threadId); if (index >= 0) { matchingResourceData.commentThreads[index] = ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread); - } else if (thread.comments && thread.comments.length) { + } else { matchingResourceData.commentThreads.push(ResourceWithCommentThreads.createCommentNode(URI.parse(matchingResourceData.id), thread)); } }); diff --git a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts index f358394759..c6d1aa593e 100644 --- a/src/vs/workbench/contrib/debug/browser/baseDebugView.ts +++ b/src/vs/workbench/contrib/debug/browser/baseDebugView.ts @@ -221,4 +221,4 @@ export abstract class AbstractExpressionsRenderer implements ITreeRenderer(); - data.set(this.breakpoint.getId(), { - condition, - hitCondition, - logMessage - }); - this.debugService.updateBreakpoints(this.breakpoint.uri, data, false); + this.debugService.updateBreakpoints(this.breakpoint.uri, { + [this.breakpoint.getId()]: { + condition, + hitCondition, + logMessage + } + }, false); } else { const model = this.editor.getModel(); if (model) { diff --git a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts index 25468d6eb1..3b9210ec0f 100644 --- a/src/vs/workbench/contrib/debug/browser/breakpointsView.ts +++ b/src/vs/workbench/contrib/debug/browser/breakpointsView.ts @@ -61,7 +61,7 @@ export class BreakpointsView extends ViewletPanel { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: nls.localize('breakpointsSection', "Breakpoints Section") }, keybindingService, contextMenuService, configurationService); this.minimumBodySize = this.maximumBodySize = this.getExpandedBodySize(); - this._register(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); + this.disposables.push(this.debugService.getModel().onDidChangeBreakpoints(() => this.onBreakpointsChange())); } public renderBody(container: HTMLElement): void { @@ -81,9 +81,9 @@ export class BreakpointsView extends ViewletPanel { CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService); - this._register(this.list.onContextMenu(this.onListContextMenu, this)); + this.list.onContextMenu(this.onListContextMenu, this, this.disposables); - this._register(this.list.onDidOpen(e => { + this.disposables.push(this.list.onDidOpen(e => { let isSingleClick = false; let isDoubleClick = false; let isMiddleClick = false; @@ -120,7 +120,7 @@ export class BreakpointsView extends ViewletPanel { this.list.splice(0, this.list.length, this.elements); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.needsRefresh) { this.onBreakpointsChange(); } @@ -557,6 +557,7 @@ export function openBreakpointSource(breakpoint: IBreakpoint, sideBySide: boolea options: { preserveFocus, selection, + revealIfVisible: true, revealIfOpened: true, revealInCenterIfOutsideViewport: true, pinned: !preserveFocus diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index 356e9cdfe8..7dca7bd8ac 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -63,7 +63,7 @@ export class CallStackView extends ViewletPanel { this.callStackItemType = CONTEXT_CALLSTACK_ITEM_TYPE.bindTo(contextKeyService); this.contributedContextMenu = menuService.createMenu(MenuId.DebugCallStackContext, contextKeyService); - this._register(this.contributedContextMenu); + this.disposables.push(this.contributedContextMenu); // Create scheduler to prevent unnecessary flashing of tree when reacting to changes this.onCallStackChangeScheduler = new RunOnceScheduler(() => { @@ -149,8 +149,8 @@ export class CallStackView extends ViewletPanel { this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError); const callstackNavigator = new TreeResourceNavigator2(this.tree); - this._register(callstackNavigator); - this._register(callstackNavigator.onDidOpenResource(e => { + this.disposables.push(callstackNavigator); + this.disposables.push(callstackNavigator.onDidOpenResource(e => { if (this.ignoreSelectionChangedEvent) { return; } @@ -189,7 +189,7 @@ export class CallStackView extends ViewletPanel { } })); - this._register(this.debugService.getModel().onDidChangeCallStack(() => { + this.disposables.push(this.debugService.getModel().onDidChangeCallStack(() => { if (!this.isBodyVisible()) { this.needsRefresh = true; return; @@ -200,7 +200,7 @@ export class CallStackView extends ViewletPanel { } })); const onCallStackChange = Event.any(this.debugService.getViewModel().onDidFocusStackFrame, this.debugService.getViewModel().onDidFocusSession); - this._register(onCallStackChange(() => { + this.disposables.push(onCallStackChange(() => { if (this.ignoreFocusStackFrameEvent) { return; } @@ -211,20 +211,20 @@ export class CallStackView extends ViewletPanel { this.updateTreeSelection(); })); - this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); + this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e))); // Schedule the update of the call stack tree if the viewlet is opened after a session started #14684 if (this.debugService.state === State.Stopped) { this.onCallStackChangeScheduler.schedule(0); } - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.needsRefresh) { this.onCallStackChangeScheduler.schedule(); } })); - this._register(this.debugService.onDidNewSession(s => { + this.disposables.push(this.debugService.onDidNewSession(s => { if (s.parentSession) { // Auto expand sessions that have sub sessions this.parentSessionToExpand.add(s.parentSession); diff --git a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts index d2b02188be..0e0b1adca8 100644 --- a/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts +++ b/src/vs/workbench/contrib/debug/browser/debugANSIHandling.ts @@ -5,14 +5,12 @@ import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { RGBA, Color } from 'vs/base/common/color'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { ansiColorIdentifiers } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; /** * @param text The content to stylize. * @returns An {@link HTMLSpanElement} that contains the potentially stylized text. */ -export function handleANSIOutput(text: string, linkDetector: LinkDetector, themeService: IThemeService): HTMLSpanElement { +export function handleANSIOutput(text: string, linkDetector: LinkDetector): HTMLSpanElement { const root: HTMLSpanElement = document.createElement('span'); const textLength: number = text.length; @@ -107,20 +105,23 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme /** * Change the foreground or background color by clearing the current color * and adding the new one. + * @param newClass If string or number, new class will be + * `code-(foreground or background)-newClass`. If `undefined`, no new class + * will be added. * @param colorType If `'foreground'`, will change the foreground color, if * `'background'`, will change the background color. - * @param color Color to change to. If `undefined` or not provided, - * will clear current color without adding a new one. + * @param customColor If provided, this custom color will be used instead of + * a class-defined color. */ - function changeColor(colorType: 'foreground' | 'background', color?: RGBA | undefined): void { - if (colorType === 'foreground') { - customFgColor = color; - } else if (colorType === 'background') { - customBgColor = color; + function changeColor(newClass: string | number | undefined, colorType: 'foreground' | 'background', customColor?: RGBA): void { + styleNames = styleNames.filter(style => !style.match(new RegExp(`^code-${colorType}-(\\d+|custom)$`))); + if (newClass) { + styleNames.push(`code-${colorType}-${newClass}`); } - styleNames = styleNames.filter(style => style !== `code-${colorType}-colored`); - if (color !== undefined) { - styleNames.push(`code-${colorType}-colored`); + if (colorType === 'foreground') { + customFgColor = customColor; + } else { + customBgColor = customColor; } } @@ -136,37 +137,22 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme */ function setBasicFormatters(styleCodes: number[]): void { for (let code of styleCodes) { - switch (code) { - case 0: { - styleNames = []; - customFgColor = undefined; - customBgColor = undefined; - break; - } - case 1: { - styleNames.push('code-bold'); - break; - } - case 3: { - styleNames.push('code-italic'); - break; - } - case 4: { - styleNames.push('code-underline'); - break; - } - case 39: { - changeColor('foreground', undefined); - break; - } - case 49: { - changeColor('background', undefined); - break; - } - default: { - setBasicColor(code); - break; - } + if (code === 0) { + styleNames = []; + } else if (code === 1) { + styleNames.push('code-bold'); + } else if (code === 3) { + styleNames.push('code-italic'); + } else if (code === 4) { + styleNames.push('code-underline'); + } else if ((code >= 30 && code <= 37) || (code >= 90 && code <= 97)) { + changeColor(code, 'foreground'); + } else if ((code >= 40 && code <= 47) || (code >= 100 && code <= 107)) { + changeColor(code, 'background'); + } else if (code === 39) { + changeColor(undefined, 'foreground'); + } else if (code === 49) { + changeColor(undefined, 'background'); } } } @@ -185,7 +171,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme styleCodes[3] >= 0 && styleCodes[3] <= 255 && styleCodes[4] >= 0 && styleCodes[4] <= 255) { const customColor = new RGBA(styleCodes[2], styleCodes[3], styleCodes[4]); - changeColor(colorType, customColor); + changeColor('custom', colorType, customColor); } } @@ -202,7 +188,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme const color = calcANSI8bitColor(colorNumber); if (color) { - changeColor(colorType, color); + changeColor('custom', colorType, color); } else if (colorNumber >= 0 && colorNumber <= 15) { // Need to map to one of the four basic color ranges (30-37, 90-97, 40-47, 100-107) colorNumber += 30; @@ -213,43 +199,7 @@ export function handleANSIOutput(text: string, linkDetector: LinkDetector, theme if (colorType === 'background') { colorNumber += 10; } - setBasicColor(colorNumber); - } - } - - /** - * Calculate and set styling for basic bright and dark ANSI color codes. Uses - * theme colors if available. Automatically distinguishes between foreground - * and background colors; does not support color-clearing codes 39 and 49. - * @param styleCode Integer color code on one of the following ranges: - * [30-37, 90-97, 40-47, 100-107]. If not on one of these ranges, will do - * nothing. - */ - function setBasicColor(styleCode: number): void { - const theme = themeService.getTheme(); - let colorType: 'foreground' | 'background' | undefined; - let colorIndex: number | undefined; - - if (styleCode >= 30 && styleCode <= 37) { - colorIndex = styleCode - 30; - colorType = 'foreground'; - } else if (styleCode >= 90 && styleCode <= 97) { - colorIndex = (styleCode - 90) + 8; // High-intensity (bright) - colorType = 'foreground'; - } else if (styleCode >= 40 && styleCode <= 47) { - colorIndex = styleCode - 40; - colorType = 'background'; - } else if (styleCode >= 100 && styleCode <= 107) { - colorIndex = (styleCode - 100) + 8; // High-intensity (bright) - colorType = 'background'; - } - - if (colorIndex !== undefined && colorType) { - const colorName = ansiColorIdentifiers[colorIndex]; - const color = theme.getColor(colorName); - if (color) { - changeColor(colorType, color.rgba); - } + changeColor(colorNumber, colorType); } } } diff --git a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts index 4ac8043eeb..7332251718 100644 --- a/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts +++ b/src/vs/workbench/contrib/debug/browser/debugActionViewItems.ts @@ -199,9 +199,9 @@ export class FocusSessionActionViewItem extends SelectActionViewItem { ) { super(null, action, [], -1, contextViewService, { ariaLabel: nls.localize('debugSession', 'Debug Session') }); - this._register(attachSelectBoxStyler(this.selectBox, themeService)); + this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService)); - this._register(this.debugService.getViewModel().onDidFocusSession(() => { + this.toDispose.push(this.debugService.getViewModel().onDidFocusSession(() => { const session = this.debugService.getViewModel().focusedSession; if (session) { const index = this.getSessions().indexOf(session); @@ -209,8 +209,8 @@ export class FocusSessionActionViewItem extends SelectActionViewItem { } })); - this._register(this.debugService.onDidNewSession(() => this.update())); - this._register(this.debugService.onDidEndSession(() => this.update())); + this.toDispose.push(this.debugService.onDidNewSession(() => this.update())); + this.toDispose.push(this.debugService.onDidEndSession(() => this.update())); this.update(); } diff --git a/src/vs/workbench/contrib/debug/browser/debugCommands.ts b/src/vs/workbench/contrib/debug/browser/debugCommands.ts index e370222b0e..0086a958e8 100644 --- a/src/vs/workbench/contrib/debug/browser/debugCommands.ts +++ b/src/vs/workbench/contrib/debug/browser/debugCommands.ts @@ -53,11 +53,6 @@ function getThreadAndRun(accessor: ServicesAccessor, thread: IThread | undefined const debugService = accessor.get(IDebugService); if (!(thread instanceof Thread)) { thread = debugService.getViewModel().focusedThread; - if (!thread) { - const focusedSession = debugService.getViewModel().focusedSession; - const threads = focusedSession ? focusedSession.getAllThreads() : undefined; - thread = threads && threads.length ? threads[0] : undefined; - } } if (thread) { @@ -412,18 +407,24 @@ export function registerCommands(): void { const widget = editorService.activeTextEditorWidget; if (isCodeEditor(widget)) { const position = widget.getPosition(); - if (position && widget.hasModel() && debugService.getConfigurationManager().canSetBreakpointsIn(widget.getModel())) { - const modelUri = widget.getModel().uri; - const breakpointAlreadySet = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri }) - .some(bp => (bp.sessionAgnosticData.column === position.column || (!bp.column && position.column <= 1))); + if (!position || !widget.hasModel()) { + return undefined; + } - if (!breakpointAlreadySet) { - debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }], 'debugCommands.inlineBreakpointCommand'); - } + const modelUri = widget.getModel().uri; + const bp = debugService.getModel().getBreakpoints({ lineNumber: position.lineNumber, uri: modelUri }) + .filter(bp => (bp.column === position.column || !bp.column && position.column <= 1)).pop(); + + if (bp) { + return undefined; + } + if (debugService.getConfigurationManager().canSetBreakpointsIn(widget.getModel())) { + return debugService.addBreakpoints(modelUri, [{ lineNumber: position.lineNumber, column: position.column > 1 ? position.column : undefined }], 'debugCommands.inlineBreakpointCommand'); } } - }; + return undefined; + }; KeybindingsRegistry.registerCommandAndKeybindingRule({ weight: KeybindingWeight.WorkbenchContrib, primary: KeyMod.Shift | KeyCode.F9, diff --git a/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts b/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts index fb099601f1..1360355d9a 100644 --- a/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugEditorModelManager.ts @@ -180,7 +180,7 @@ export class DebugEditorModelManager implements IWorkbenchContribution { return; } - const data = new Map(); + const data: { [id: string]: IBreakpointUpdateData } = Object.create(null); const breakpoints = this.debugService.getModel().getBreakpoints(); const modelUri = modelData.model.uri; for (let i = 0, len = modelData.breakpointDecorations.length; i < len; i++) { @@ -191,10 +191,10 @@ export class DebugEditorModelManager implements IWorkbenchContribution { const breakpoint = breakpoints.filter(bp => bp.getId() === breakpointDecoration.modelId).pop(); // since we know it is collapsed, it cannot grow to multiple lines if (breakpoint) { - data.set(breakpoint.getId(), { + data[breakpoint.getId()] = { lineNumber: decorationRange.startLineNumber, column: breakpoint.column ? decorationRange.startColumn : undefined, - }); + }; } } } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 994f93fa49..120e40e5d0 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -16,7 +16,7 @@ import { IContentWidget, ICodeEditor, IContentWidgetPosition, ContentWidgetPosit import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IDebugService, IExpression, IExpressionContainer } from 'vs/workbench/contrib/debug/common/debug'; import { Expression } from 'vs/workbench/contrib/debug/common/debugModel'; -import { renderExpressionValue, replaceWhitespace } from 'vs/workbench/contrib/debug/browser/baseDebugView'; +import { renderExpressionValue } from 'vs/workbench/contrib/debug/browser/baseDebugView'; import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableElement'; import { attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; @@ -237,7 +237,7 @@ export class DebugHoverWidget implements IContentWidget { this.complexValueContainer.hidden = false; return this.tree.setInput(expression).then(() => { - this.complexValueTitle.textContent = replaceWhitespace(expression.value); + this.complexValueTitle.textContent = expression.value; this.complexValueTitle.title = expression.value; this.layoutTreeAndContainer(); this.editor.layoutContentWidget(this); diff --git a/src/vs/workbench/contrib/debug/browser/debugStatus.ts b/src/vs/workbench/contrib/debug/browser/debugStatus.ts index 2ae12585b4..f0b7891e8f 100644 --- a/src/vs/workbench/contrib/debug/browser/debugStatus.ts +++ b/src/vs/workbench/contrib/debug/browser/debugStatus.ts @@ -4,81 +4,100 @@ *--------------------------------------------------------------------------------------------*/ import * as nls from 'vs/nls'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import * as dom from 'vs/base/browser/dom'; +import { IDisposable } from 'vs/base/common/lifecycle'; +import { IQuickOpenService } from 'vs/platform/quickOpen/common/quickOpen'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; import { IDebugService, State, IDebugConfiguration } from 'vs/workbench/contrib/debug/common/debug'; +import { Themable, STATUS_BAR_FOREGROUND } from 'vs/workbench/common/theme'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IStatusbarEntry, IStatusbarService, StatusbarAlignment, IStatusbarEntryAccessor } from 'vs/platform/statusbar/common/statusbar'; -import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { STATUS_BAR_DEBUGGING_FOREGROUND, isStatusbarInDebugMode } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider'; +const $ = dom.$; -export class DebugStatusContribution implements IWorkbenchContribution { - +export class DebugStatus extends Themable implements IStatusbarItem { + private container: HTMLElement; + private statusBarItem: HTMLElement; + private label: HTMLElement; + private icon: HTMLElement; private showInStatusBar: 'never' | 'always' | 'onFirstSessionStart'; - private toDispose: IDisposable[] = []; - private entryAccessor: IStatusbarEntryAccessor | undefined; constructor( - @IStatusbarService private readonly statusBarService: IStatusbarService, - @IDebugService readonly debugService: IDebugService, - @IConfigurationService readonly configurationService: IConfigurationService + @IQuickOpenService private readonly quickOpenService: IQuickOpenService, + @IDebugService private readonly debugService: IDebugService, + @IThemeService themeService: IThemeService, + @IConfigurationService configurationService: IConfigurationService ) { - - const addStatusBarEntry = () => { - this.entryAccessor = this.statusBarService.addEntry(this.entry, 'status.debug', nls.localize('status.debug', "Debug"), StatusbarAlignment.LEFT, 30 /* Low Priority */); - }; - - const setShowInStatusBar = () => { - this.showInStatusBar = configurationService.getValue('debug').showInStatusBar; - if (this.showInStatusBar === 'always' && !this.entryAccessor) { - addStatusBarEntry(); - } - }; - setShowInStatusBar(); - - this.toDispose.push(this.debugService.onDidChangeState(state => { - if (state !== State.Inactive && this.showInStatusBar === 'onFirstSessionStart' && !this.entryAccessor) { - addStatusBarEntry(); - } + super(themeService); + this._register(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => { + this.setLabel(); })); - this.toDispose.push(configurationService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('debug.showInStatusBar')) { - setShowInStatusBar(); - if (this.entryAccessor && this.showInStatusBar === 'never') { - this.entryAccessor.dispose(); - this.entryAccessor = undefined; + this._register(this.debugService.onDidChangeState(state => { + if (state !== State.Inactive && this.showInStatusBar === 'onFirstSessionStart') { + this.doRender(); + } else { + if (this.showInStatusBar !== 'never') { + this.updateStyles(); } } })); - this.toDispose.push(this.debugService.getConfigurationManager().onDidSelectConfiguration(e => { - if (this.entryAccessor) { - this.entryAccessor.update(this.entry); + this.showInStatusBar = configurationService.getValue('debug').showInStatusBar; + this._register(configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('debug.showInStatusBar')) { + this.showInStatusBar = configurationService.getValue('debug').showInStatusBar; + if (this.showInStatusBar === 'always') { + this.doRender(); + } + if (this.statusBarItem) { + dom.toggleClass(this.statusBarItem, 'hidden', this.showInStatusBar === 'never'); + } } })); } - private getText(): string { - const manager = this.debugService.getConfigurationManager(); - const name = manager.selectedConfiguration.name || ''; - const nameAndLaunchPresent = name && manager.selectedConfiguration.launch; - if (nameAndLaunchPresent) { - return '$(play) ' + (manager.getLaunches().length > 1 ? `${name} (${manager.selectedConfiguration.launch!.name})` : name); + protected updateStyles(): void { + if (this.icon) { + if (isStatusbarInDebugMode(this.debugService)) { + this.icon.style.backgroundColor = this.getColor(STATUS_BAR_DEBUGGING_FOREGROUND); + } else { + this.icon.style.backgroundColor = this.getColor(STATUS_BAR_FOREGROUND); + } } - - return ''; } - private get entry(): IStatusbarEntry { - return { - text: this.getText(), - tooltip: nls.localize('selectAndStartDebug', "Select and start debug configuration"), - command: 'workbench.action.debug.selectandstart' - }; + public render(container: HTMLElement): IDisposable { + this.container = container; + if (this.showInStatusBar === 'always') { + this.doRender(); + } + // noop, we render when we decide is best + return this; } - dispose(): void { - if (this.entryAccessor) { - this.entryAccessor.dispose(); + private doRender(): void { + if (!this.statusBarItem && this.container) { + this.statusBarItem = dom.append(this.container, $('.debug-statusbar-item')); + this._register(dom.addDisposableListener(this.statusBarItem, 'click', () => this.quickOpenService.show('debug '))); + this.statusBarItem.title = nls.localize('selectAndStartDebug', "Select and start debug configuration"); + const a = dom.append(this.statusBarItem, $('a')); + this.icon = dom.append(a, $('.icon')); + this.label = dom.append(a, $('span.label')); + this.setLabel(); + } + + this.updateStyles(); + } + + private setLabel(): void { + if (this.label && this.statusBarItem) { + const manager = this.debugService.getConfigurationManager(); + const name = manager.selectedConfiguration.name || ''; + const nameAndLaunchPresent = name && manager.selectedConfiguration.launch; + dom.toggleClass(this.statusBarItem, 'hidden', this.showInStatusBar === 'never' || !nameAndLaunchPresent); + if (nameAndLaunchPresent) { + this.label.textContent = manager.getLaunches().length > 1 ? `${name} (${manager.selectedConfiguration.launch!.name})` : name; + } } - dispose(this.toDispose); } } diff --git a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts index 2685a94ba5..005a4590f3 100644 --- a/src/vs/workbench/contrib/debug/browser/debugToolBar.ts +++ b/src/vs/workbench/contrib/debug/browser/debugToolBar.ts @@ -81,7 +81,7 @@ export class DebugToolBar extends Themable implements IWorkbenchContribution { const actionBarContainer = dom.append(this.$el, dom.$('div.action-bar-container')); this.debugToolBarMenu = menuService.createMenu(MenuId.DebugToolBar, contextKeyService); - this._register(this.debugToolBarMenu); + this.toDispose.push(this.debugToolBarMenu); this.activeActions = []; this.actionBar = this._register(new ActionBar(actionBarContainer, { diff --git a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts index 8ee288b682..a823479349 100644 --- a/src/vs/workbench/contrib/debug/browser/debugViewlet.ts +++ b/src/vs/workbench/contrib/debug/browser/debugViewlet.ts @@ -14,7 +14,7 @@ import { StartAction, ConfigureAction, SelectAndStartAction, FocusSessionAction import { StartDebugActionViewItem, FocusSessionActionViewItem } from 'vs/workbench/contrib/debug/browser/debugActionViewItems'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -37,7 +37,7 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; export class DebugViewlet extends ViewContainerViewlet { private startDebugActionViewItem: StartDebugActionViewItem; - private progressResolve: (() => void) | undefined; + private progressRunner: IProgressRunner; private breakpointView: ViewletPanel; private panelListeners = new Map(); private debugToolBarMenu: IMenu; @@ -112,7 +112,7 @@ export class DebugViewlet extends ViewContainerViewlet { if (!this.debugToolBarMenu) { this.debugToolBarMenu = this.menuService.createMenu(MenuId.DebugToolBar, this.contextKeyService); - this._register(this.debugToolBarMenu); + this.toDispose.push(this.debugToolBarMenu); } return DebugToolBar.getActions(this.debugToolBarMenu, this.debugService, this.instantiationService); } @@ -153,15 +153,12 @@ export class DebugViewlet extends ViewContainerViewlet { } private onDebugServiceStateChange(state: State): void { - if (this.progressResolve) { - this.progressResolve(); - this.progressResolve = undefined; + if (this.progressRunner) { + this.progressRunner.done(); } if (state === State.Initializing) { - this.progressService.withProgress({ location: VIEWLET_ID }, _progress => { - return new Promise(resolve => this.progressResolve = resolve); - }); + this.progressRunner = this.progressService.show(true); } this.updateToolBar(); diff --git a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts index c1a59834aa..cbe90c6377 100644 --- a/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts +++ b/src/vs/workbench/contrib/debug/browser/exceptionWidget.ts @@ -35,12 +35,12 @@ export class ExceptionWidget extends ZoneWidget { this._backgroundColor = Color.white; this._applyTheme(themeService.getTheme()); - this._disposables.add(themeService.onThemeChange(this._applyTheme.bind(this))); + this._disposables.push(themeService.onThemeChange(this._applyTheme.bind(this))); this.create(); const onDidLayoutChangeScheduler = new RunOnceScheduler(() => this._doLayout(undefined, undefined), 50); - this._disposables.add(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule())); - this._disposables.add(onDidLayoutChangeScheduler); + this._disposables.push(this.editor.onDidLayoutChange(() => onDidLayoutChangeScheduler.schedule())); + this._disposables.push(onDidLayoutChangeScheduler); } private _applyTheme(theme: ITheme): void { diff --git a/src/vs/workbench/contrib/debug/browser/linkDetector.ts b/src/vs/workbench/contrib/debug/browser/linkDetector.ts index 318895d585..df8c8ea403 100644 --- a/src/vs/workbench/contrib/debug/browser/linkDetector.ts +++ b/src/vs/workbench/contrib/debug/browser/linkDetector.ts @@ -19,7 +19,7 @@ export class LinkDetector { // group 2: drive letter on windows with trailing backslash or leading slash on mac/linux // group 3: line number, matched by (:(\d+)) // group 4: column number, matched by ((?::(\d+))?) - // e.g.: at Context. (c:\Users\someone\Desktop\mocha-runner\test\test.js:26:11) + // eg: at Context. (c:\Users\someone\Desktop\mocha-runner\test\test.js:26:11) /(?![\(])(?:file:\/\/)?((?:([a-zA-Z]+:)|[^\(\)<>\'\"\[\]:\s]+)(?:[\\/][^\(\)<>\'\"\[\]:]*)?\.[a-zA-Z]+[0-9]*):(\d+)(?::(\d+))?/g ]; diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index 7a79130873..298a7604a1 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -45,15 +45,16 @@ type LoadedScriptsItem = BaseTreeItem; class BaseTreeItem { private _showedMoreThanOne: boolean; - private _children = new Map(); + private _children: { [key: string]: BaseTreeItem; }; private _source: Source; constructor(private _parent: BaseTreeItem | undefined, private _label: string) { + this._children = {}; this._showedMoreThanOne = false; } isLeaf(): boolean { - return this._children.size === 0; + return Object.keys(this._children).length === 0; } getSession(): IDebugSession | undefined { @@ -65,12 +66,12 @@ class BaseTreeItem { setSource(session: IDebugSession, source: Source): void { this._source = source; - this._children.clear(); + this._children = {}; if (source.raw && source.raw.sources) { for (const src of source.raw.sources) { if (src.name && src.path) { const s = new BaseTreeItem(this, src.name); - this._children.set(src.path, s); + this._children[src.path] = s; const ss = session.getSource(src); s.setSource(session, ss); } @@ -79,26 +80,26 @@ class BaseTreeItem { } createIfNeeded(key: string, factory: (parent: BaseTreeItem, label: string) => T): T { - let child = this._children.get(key); + let child = this._children[key]; if (!child) { child = factory(this, key); - this._children.set(key, child); + this._children[key] = child; } return child; } - getChild(key: string): BaseTreeItem | undefined { - return this._children.get(key); + getChild(key: string): BaseTreeItem { + return this._children[key]; } remove(key: string): void { - this._children.delete(key); + delete this._children[key]; } removeFromParent(): void { if (this._parent) { this._parent.remove(this._label); - if (this._parent._children.size === 0) { + if (Object.keys(this._parent._children).length === 0) { this._parent.removeFromParent(); } } @@ -141,7 +142,7 @@ class BaseTreeItem { if (child) { return child.hasChildren(); } - return this._children.size > 0; + return Object.keys(this._children).length > 0; } // skips intermediate single-child nodes @@ -150,10 +151,7 @@ class BaseTreeItem { if (child) { return child.getChildren(); } - const array: BaseTreeItem[] = []; - for (let child of this._children.values()) { - array.push(child); - } + const array = Object.keys(this._children).map(key => this._children[key]); return Promise.resolve(array.sort((a, b) => this.compare(a, b))); } @@ -201,11 +199,12 @@ class BaseTreeItem { private oneChild(): BaseTreeItem | undefined { if (SMART && !this._source && !this._showedMoreThanOne && !(this instanceof RootFolderTreeItem) && !(this instanceof SessionTreeItem)) { - if (this._children.size === 1) { - return this._children.values().next().value; + const keys = Object.keys(this._children); + if (keys.length === 1) { + return this._children[keys[0]]; } // if a node had more than one child once, it will never be skipped again - if (this._children.size > 1) { + if (keys.length > 1) { this._showedMoreThanOne = true; } } @@ -244,7 +243,7 @@ class SessionTreeItem extends BaseTreeItem { private _session: IDebugSession; private _initialized: boolean; - private _map = new Map(); + private _map: Map; private _labelService: ILabelService; constructor(labelService: ILabelService, parent: BaseTreeItem, session: IDebugSession, private _environmentService: IEnvironmentService, private rootProvider: IWorkspaceContextService) { @@ -252,6 +251,7 @@ class SessionTreeItem extends BaseTreeItem { this._labelService = labelService; this._initialized = false; this._session = session; + this._map = new Map(); } getSession(): IDebugSession { @@ -417,7 +417,7 @@ export class LoadedScriptsView extends ViewletPanel { const root = new RootTreeItem(this.debugService.getModel(), this.environmentService, this.contextService, this.labelService); this.treeLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); - this._register(this.treeLabels); + this.disposables.push(this.treeLabels); this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, this.treeContainer, new LoadedScriptsDelegate(), [new LoadedScriptsRenderer(this.treeLabels)], @@ -443,11 +443,11 @@ export class LoadedScriptsView extends ViewletPanel { this.tree.updateChildren(); } }, 300); - this._register(this.changeScheduler); + this.disposables.push(this.changeScheduler); const loadedScriptsNavigator = new TreeResourceNavigator2(this.tree); - this._register(loadedScriptsNavigator); - this._register(loadedScriptsNavigator.onDidOpenResource(e => { + this.disposables.push(loadedScriptsNavigator); + this.disposables.push(loadedScriptsNavigator.onDidOpenResource(e => { if (e.element instanceof BaseTreeItem) { const source = e.element.getSource(); if (source && source.available) { @@ -457,7 +457,7 @@ export class LoadedScriptsView extends ViewletPanel { } })); - this._register(this.tree.onDidChangeFocus(() => { + this.disposables.push(this.tree.onDidChangeFocus(() => { const focus = this.tree.getFocus(); if (focus instanceof SessionTreeItem) { this.loadedScriptsItemType.set('session'); @@ -467,7 +467,7 @@ export class LoadedScriptsView extends ViewletPanel { })); const registerLoadedSourceListener = (session: IDebugSession) => { - this._register(session.onDidLoadedSource(event => { + this.disposables.push(session.onDidLoadedSource(event => { let sessionRoot: SessionTreeItem; switch (event.reason) { case 'new': @@ -501,17 +501,17 @@ export class LoadedScriptsView extends ViewletPanel { })); }; - this._register(this.debugService.onDidNewSession(registerLoadedSourceListener)); + this.disposables.push(this.debugService.onDidNewSession(registerLoadedSourceListener)); this.debugService.getModel().getSessions().forEach(registerLoadedSourceListener); - this._register(this.debugService.onDidEndSession(session => { + this.disposables.push(this.debugService.onDidEndSession(session => { root.remove(session.getId()); this.changeScheduler.schedule(); })); this.changeScheduler.schedule(0); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.treeNeedsRefreshOnVisible) { this.changeScheduler.schedule(); } diff --git a/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css b/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css index b680b2806e..1d3e15fbef 100644 --- a/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css +++ b/src/vs/workbench/contrib/debug/browser/media/breakpointWidget.css @@ -18,5 +18,6 @@ .monaco-editor .zone-widget .zone-widget-container.breakpoint-widget .inputContainer { flex: 1; - margin-top: 8px; + margin-top: 6px; + margin-bottom: 6px; } diff --git a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css index f42d0408e4..36af227a4d 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css +++ b/src/vs/workbench/contrib/debug/browser/media/debug.contribution.css @@ -110,6 +110,25 @@ box-sizing: border-box; } +/* Debug status */ +/* A very precise css rule to overwrite the display set in statusbar.css */ +.monaco-workbench .part.statusbar > .statusbar-item > .debug-statusbar-item > a { + display: flex; + padding: 0 5px 0 5px; +} + +.monaco-workbench .part.statusbar .debug-statusbar-item.hidden { + display: none; +} + +.monaco-workbench .part.statusbar .debug-statusbar-item .icon { + -webkit-mask: url('start.svg') no-repeat 50% 50%; + -webkit-mask-size: 16px; + display: inline-block; + padding-right: 2px; + width: 16px; +} + .monaco-workbench .debug-view-content .monaco-list-row .monaco-tl-contents { overflow: hidden; text-overflow: ellipsis; @@ -123,7 +142,6 @@ overflow: hidden; text-overflow: ellipsis; font-family: var(--monaco-monospace-font); - white-space: pre; } .monaco-workbench.mac .debug-viewlet .monaco-list-row .expression, diff --git a/src/vs/workbench/contrib/debug/browser/media/debugHover.css b/src/vs/workbench/contrib/debug/browser/media/debugHover.css index 74cbf74404..45bc2bebef 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugHover.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugHover.css @@ -26,7 +26,6 @@ text-overflow: ellipsis; height: 18px; overflow: hidden; - white-space: pre; border-bottom: 1px solid rgba(128, 128, 128, 0.35); } @@ -61,6 +60,10 @@ max-height: 500px; } +.monaco-editor .debug-hover-widget .monaco-tl-contents .value { + white-space: nowrap; +} + .monaco-editor .debug-hover-widget .error { color: #E51400; } diff --git a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css index 7c86780766..4c4f832c40 100644 --- a/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css +++ b/src/vs/workbench/contrib/debug/browser/media/debugViewlet.css @@ -246,6 +246,10 @@ opacity: 0.35; } +.monaco-workbench .debug-viewlet .monaco-list-row .expression { + white-space: pre; +} + .debug-viewlet .debug-call-stack .error { font-style: italic; text-overflow: ellipsis; diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 3a3e6b50a5..38c5d28b1d 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -127,6 +127,61 @@ .monaco-workbench .repl .repl-tree .output.expression .code-italic { font-style: italic; } .monaco-workbench .repl .repl-tree .output.expression .code-underline { text-decoration: underline; } +/* Regular and bright color codes are currently treated the same. */ +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-30, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-90 { color: gray; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-31, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-91 { color: #BE1717; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-32, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-92 { color: #338A2F; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-33, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-93 { color: #BEB817; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-34, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-94 { color: darkblue; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-35, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-95 { color: darkmagenta; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-36, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-96 { color: darkcyan; } +.monaco-workbench .repl .repl-tree .output.expression .code-foreground-37, .monaco-workbench .repl .repl-tree .output.expression .code-foreground-97 { color: #BDBDBD; } + +.monaco-workbench .repl .repl-tree .output.expression .code-background-40, .monaco-workbench .repl .repl-tree .output.expression .code-background-100 { background-color: gray; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-41, .monaco-workbench .repl .repl-tree .output.expression .code-background-101 { background-color: #BE1717; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-42, .monaco-workbench .repl .repl-tree .output.expression .code-background-102 { background-color: #338A2F; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-43, .monaco-workbench .repl .repl-tree .output.expression .code-background-103 { background-color: #BEB817; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-44, .monaco-workbench .repl .repl-tree .output.expression .code-background-104 { background-color: darkblue; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-45, .monaco-workbench .repl .repl-tree .output.expression .code-background-105 { background-color: darkmagenta; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-46, .monaco-workbench .repl .repl-tree .output.expression .code-background-106 { background-color: darkcyan; } +.monaco-workbench .repl .repl-tree .output.expression .code-background-47, .monaco-workbench .repl .repl-tree .output.expression .code-background-107 { background-color: #BDBDBD; } + +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-30, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-90 { color: #A0A0A0; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-31, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-91 { color: #A74747; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-32, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-92 { color: #348F34; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-33, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-93 { color: #5F4C29; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-34, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-94 { color: #6286BB; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-35, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-95 { color: #914191; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-36, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-96 { color: #218D8D; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-37, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-foreground-97 { color: #707070; } + +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-40, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-100 { background-color: #A0A0A0; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-41, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-101 { background-color: #A74747; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-42, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-102 { background-color: #348F34; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-43, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-103 { background-color: #5F4C29; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-44, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-104 { background-color: #6286BB; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-45, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-105 { background-color: #914191; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-46, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-106 { background-color: #218D8D; } +.vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-47, .vs-dark .monaco-workbench .repl .repl-tree .output.expression .code-background-107 { background-color: #707070; } + +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-30, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-90 { color: gray; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-31, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-91 { color: #A74747; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-32, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-92 { color: #348F34; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-33, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-93 { color: #5F4C29; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-34, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-94 { color: #6286BB; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-35, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-95 { color: #914191; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-36, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-96 { color: #218D8D; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-37, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-foreground-97 { color: #707070; } + +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-40, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-100 { background-color: gray; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-41, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-101 { background-color: #A74747; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-42, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-102 { background-color: #348F34; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-43, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-103 { background-color: #5F4C29; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-44, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-104 { background-color: #6286BB; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-45, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-105 { background-color: #914191; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-46, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-106 { background-color: #218D8D; } +.hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-47, .hc-black .monaco-workbench .repl .repl-tree .output.expression .code-background-107 { background-color: #707070; } + /* Links */ .monaco-workbench .repl .repl-tree .output.expression a { text-decoration: underline; diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 58716135f9..ca293d8b2e 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -11,7 +11,7 @@ import { IAction, IActionViewItem, Action } from 'vs/base/common/actions'; import * as dom from 'vs/base/browser/dom'; import * as aria from 'vs/base/browser/ui/aria/aria'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { KeyCode, KeyMod } from 'vs/base/common/keyCodes'; +import { KeyCode } from 'vs/base/common/keyCodes'; import severity from 'vs/base/common/severity'; import { SuggestController } from 'vs/editor/contrib/suggest/suggestController'; import { ITextModel } from 'vs/editor/common/model'; @@ -76,7 +76,6 @@ interface IPrivateReplService { getVisibleContent(): string; selectSession(session?: IDebugSession): void; clearRepl(): void; - focusRepl(): void; } function revealLastElement(tree: WorkbenchAsyncDataTree) { @@ -134,16 +133,15 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati } this.selectSession(); })); - this._register(this.debugService.onWillNewSession(newSession => { + this._register(this.debugService.onWillNewSession(() => { // Need to listen to output events for sessions which are not yet fully initialised const input = this.tree.getInput(); if (!input || input.state === State.Inactive) { - this.selectSession(newSession); + this.selectSession(); } this.updateTitleArea(); })); this._register(this.themeService.onThemeChange(() => { - this.refreshReplElements(false); if (this.isVisible()) { this.updateInputDecoration(); } @@ -183,10 +181,6 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.navigateHistory(false); } - focusRepl(): void { - this.tree.domFocus(); - } - private onDidFontChange(): void { if (this.styleElement) { const debugConsole = this.configurationService.getValue('debug').console; @@ -288,7 +282,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati const lineDelimiter = this.textResourcePropertiesService.getEOL(this.model.uri); const traverseAndAppend = (node: ITreeNode) => { node.children.forEach(child => { - text += child.element.toString().trimRight() + lineDelimiter; + text += child.element.toString() + lineDelimiter; if (!child.collapsed && child.children.length) { traverseAndAppend(child); } @@ -387,16 +381,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati supportDynamicHeights: true }) as WorkbenchAsyncDataTree; - this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); - let lastSelectedString: string; - this._register(this.tree.onMouseClick(() => { - const selection = window.getSelection(); - if (!selection || selection.type !== 'Range' || lastSelectedString === selection.toString()) { - // only focus the input if the user is not currently selecting. - this.replInput.focus(); - } - lastSelectedString = selection ? selection.toString() : ''; - })); + this.toDispose.push(this.tree.onContextMenu(e => this.onContextMenu(e))); // Make sure to select the session if debugging is already active this.selectSession(); this.styleElement = dom.createStyleSheet(this.container); @@ -621,8 +606,7 @@ class ReplSimpleElementsRenderer implements ITreeRenderer { - SuggestController.get(editor).acceptSelectedSuggestion(); - accessor.get(IPrivateReplService).focusRepl(); - } -} - class ReplCopyAllAction extends EditorAction { constructor() { @@ -889,7 +851,6 @@ class ReplCopyAllAction extends EditorAction { registerEditorAction(AcceptReplInputAction); registerEditorAction(ReplCopyAllAction); -registerEditorAction(FilterReplAction); class SelectReplActionViewItem extends FocusSessionActionViewItem { diff --git a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts index ea4b795364..79cbd0b3d6 100644 --- a/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts +++ b/src/vs/workbench/contrib/debug/browser/statusbarColorProvider.ts @@ -79,7 +79,7 @@ export class StatusBarColorProvider extends Themable implements IWorkbenchContri this.styleElement = createStyleSheet(container); } - this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .items-container > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor} !important; }`; + this.styleElement.innerHTML = `.monaco-workbench .part.statusbar > .statusbar-item.has-beak:before { border-bottom-color: ${backgroundColor} !important; }`; } private getColorKey(noFolderColor: string, debuggingColor: string, normalColor: string): string { @@ -115,6 +115,6 @@ export function isStatusbarInDebugMode(debugService: IDebugService): boolean { registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const statusBarItemDebuggingForeground = theme.getColor(STATUS_BAR_DEBUGGING_FOREGROUND); if (statusBarItemDebuggingForeground) { - collector.addRule(`.monaco-workbench .part.statusbar.debugging > .items-container > .statusbar-item .mask-icon { background-color: ${statusBarItemDebuggingForeground} !important; }`); + collector.addRule(`.monaco-workbench .part.statusbar.debugging > .statusbar-item .mask-icon { background-color: ${statusBarItemDebuggingForeground} !important; }`); } }); diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index 8c39f01324..b1da22b526 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -88,7 +88,7 @@ export class VariablesView extends ViewletPanel { this.toolbar.setActions([collapseAction])(); this.tree.updateChildren(); - this._register(this.debugService.getViewModel().onDidFocusStackFrame(sf => { + this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(sf => { if (!this.isBodyVisible()) { this.needsRefresh = true; return; @@ -99,16 +99,16 @@ export class VariablesView extends ViewletPanel { const timeout = sf.explicit ? 0 : undefined; this.onFocusStackFrameScheduler.schedule(timeout); })); - this._register(variableSetEmitter.event(() => this.tree.updateChildren())); - this._register(this.tree.onMouseDblClick(e => this.onMouseDblClick(e))); - this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); + this.disposables.push(variableSetEmitter.event(() => this.tree.updateChildren())); + this.disposables.push(this.tree.onMouseDblClick(e => this.onMouseDblClick(e))); + this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e))); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.needsRefresh) { this.onFocusStackFrameScheduler.schedule(); } })); - this._register(this.debugService.getViewModel().onDidSelectExpression(e => { + this.disposables.push(this.debugService.getViewModel().onDidSelectExpression(e => { if (e instanceof Variable) { this.tree.rerender(e); } diff --git a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts index d60223c4eb..e5e2707bbe 100644 --- a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts +++ b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts @@ -76,16 +76,16 @@ export class WatchExpressionsView extends ViewletPanel { const removeAllWatchExpressionsAction = new RemoveAllWatchExpressionsAction(RemoveAllWatchExpressionsAction.ID, RemoveAllWatchExpressionsAction.LABEL, this.debugService, this.keybindingService); this.toolbar.setActions([addWatchExpressionAction, collapseAction, removeAllWatchExpressionsAction])(); - this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); - this._register(this.tree.onMouseDblClick(e => this.onMouseDblClick(e))); - this._register(this.debugService.getModel().onDidChangeWatchExpressions(we => { + this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e))); + this.disposables.push(this.tree.onMouseDblClick(e => this.onMouseDblClick(e))); + this.disposables.push(this.debugService.getModel().onDidChangeWatchExpressions(we => { if (!this.isBodyVisible()) { this.needsRefresh = true; } else { this.tree.updateChildren(); } })); - this._register(this.debugService.getViewModel().onDidFocusStackFrame(() => { + this.disposables.push(this.debugService.getViewModel().onDidFocusStackFrame(() => { if (!this.isBodyVisible()) { this.needsRefresh = true; return; @@ -95,14 +95,14 @@ export class WatchExpressionsView extends ViewletPanel { this.onWatchExpressionsUpdatedScheduler.schedule(); } })); - this._register(variableSetEmitter.event(() => this.tree.updateChildren())); + this.disposables.push(variableSetEmitter.event(() => this.tree.updateChildren())); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.needsRefresh) { this.onWatchExpressionsUpdatedScheduler.schedule(); } })); - this._register(this.debugService.getViewModel().onDidSelectExpression(e => { + this.disposables.push(this.debugService.getViewModel().onDidSelectExpression(e => { if (e instanceof Expression && e.name) { this.tree.rerender(e); } diff --git a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts index 238064428c..772a9d368a 100644 --- a/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts +++ b/src/vs/workbench/contrib/debug/common/abstractDebugAdapter.ts @@ -13,7 +13,7 @@ import { IDebugAdapter } from 'vs/workbench/contrib/debug/common/debug'; export abstract class AbstractDebugAdapter implements IDebugAdapter { private sequence: number; - private pendingRequests = new Map void>(); + private pendingRequests: Map void>; private requestCallback: (request: DebugProtocol.Request) => void; private eventCallback: (request: DebugProtocol.Event) => void; private messageCallback: (message: DebugProtocol.ProtocolMessage) => void; @@ -22,6 +22,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { constructor() { this.sequence = 1; + this.pendingRequests = new Map(); this._onError = new Emitter(); this._onExit = new Emitter(); } @@ -138,7 +139,7 @@ export abstract class AbstractDebugAdapter implements IDebugAdapter { protected cancelPending() { const pending = this.pendingRequests; - this.pendingRequests.clear(); + this.pendingRequests = new Map(); setTimeout(_ => { pending.forEach((callback, request_seq) => { const err: DebugProtocol.Response = { diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index dc9cdb8af4..24e6750613 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -11,7 +11,7 @@ import { IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IEditorContribution } from 'vs/editor/common/editorCommon'; import { ITextModel as EditorIModel } from 'vs/editor/common/model'; -import { IEditor, ITextEditor } from 'vs/workbench/common/editor'; +import { IEditor } from 'vs/workbench/common/editor'; import { Position } from 'vs/editor/common/core/position'; import { CompletionItem } from 'vs/editor/common/modes'; import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; @@ -298,7 +298,7 @@ export interface IStackFrame extends ITreeElement { getSpecificSourceName(): string; restart(): Promise; toString(): string; - openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise; + openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean): Promise; } export interface IEnablement extends ITreeElement { @@ -339,7 +339,6 @@ export interface IBreakpoint extends IBaseBreakpoint { readonly endColumn?: number; readonly message?: string; readonly adapterData: any; - readonly sessionAgnosticData: { lineNumber: number, column: number | undefined }; } export interface IFunctionBreakpoint extends IBaseBreakpoint { @@ -718,7 +717,7 @@ export interface IDebugService { /** * Updates the breakpoints. */ - updateBreakpoints(uri: uri, data: Map, sendOnResourceSaved: boolean): void; + updateBreakpoints(uri: uri, data: { [id: string]: IBreakpointUpdateData }, sendOnResourceSaved: boolean): void; /** * Enables or disables all breakpoints. If breakpoint is passed only enables or disables the passed breakpoint. diff --git a/src/vs/workbench/contrib/debug/common/debugModel.ts b/src/vs/workbench/contrib/debug/common/debugModel.ts index 1f8f759792..507cc0682a 100644 --- a/src/vs/workbench/contrib/debug/common/debugModel.ts +++ b/src/vs/workbench/contrib/debug/common/debugModel.ts @@ -23,7 +23,6 @@ import { commonSuffixLength } from 'vs/base/common/strings'; import { posix } from 'vs/base/common/path'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { ITextEditor } from 'vs/workbench/common/editor'; export class SimpleReplElement implements IReplElement { constructor( @@ -90,7 +89,7 @@ export class RawObjectReplElement implements IExpression { export class ExpressionContainer implements IExpressionContainer { - public static allValues = new Map(); + public static allValues: Map = new Map(); // Use chunks to support variable paging #9537 private static readonly BASE_CHUNK_SIZE = 100; @@ -303,7 +302,7 @@ export class Scope extends ExpressionContainer implements IScope { indexedVariables?: number, public range?: IRange ) { - super(stackFrame.thread.session, reference, `scope:${name}:${index}`, namedVariables, indexedVariables); + super(stackFrame.thread.session, reference, `scope:${stackFrame.getId()}:${name}:${index}`, namedVariables, indexedVariables); } toString(): string { @@ -388,7 +387,7 @@ export class StackFrame implements IStackFrame { return sourceToString === UNKNOWN_SOURCE_LABEL ? this.name : `${this.name} (${sourceToString})`; } - openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { + openInEditor(editorService: IEditorService, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { return !this.source.available ? Promise.resolve(null) : this.source.openInEditor(editorService, this.range, preserveFocus, sideBySide, pinned); } @@ -660,13 +659,6 @@ export class Breakpoint extends BaseBreakpoint implements IBreakpoint { return data ? data.endColumn : undefined; } - get sessionAgnosticData(): { lineNumber: number, column: number | undefined } { - return { - lineNumber: this._lineNumber, - column: this._column - }; - } - setSessionData(sessionId: string, data: DebugProtocol.Breakpoint): void { super.setSessionData(sessionId, data); if (!this._adapterData) { @@ -962,10 +954,10 @@ export class DebugModel implements IDebugModel { this._onDidChangeBreakpoints.fire({ removed: toRemove }); } - updateBreakpoints(data: Map): void { + updateBreakpoints(data: { [id: string]: IBreakpointUpdateData }): void { const updated: IBreakpoint[] = []; this.breakpoints.forEach(bp => { - const bpData = data.get(bp.getId()); + const bpData = data[bp.getId()]; if (bpData) { bp.update(bpData); updated.push(bp); @@ -975,15 +967,15 @@ export class DebugModel implements IDebugModel { this._onDidChangeBreakpoints.fire({ changed: updated }); } - setBreakpointSessionData(sessionId: string, data: Map): void { + setBreakpointSessionData(sessionId: string, data: { [id: string]: DebugProtocol.Breakpoint }): void { this.breakpoints.forEach(bp => { - const bpData = data.get(bp.getId()); + const bpData = data[bp.getId()]; if (bpData) { bp.setSessionData(sessionId, bpData); } }); this.functionBreakpoints.forEach(fbp => { - const fbpData = data.get(fbp.getId()); + const fbpData = data[fbp.getId()]; if (fbpData) { fbp.setSessionData(sessionId, fbpData); } diff --git a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts index 513d0383d1..8920ff9a24 100644 --- a/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts +++ b/src/vs/workbench/contrib/debug/common/debugProtocol.d.ts @@ -240,8 +240,6 @@ declare module DebugProtocol { 'attachForSuspendedLaunch': A project launcher component has launched a new process in a suspended state and then asked the debugger to attach. */ startMethod?: 'launch' | 'attach' | 'attachForSuspendedLaunch'; - /** The size of a pointer or address for this process, in bits. This value may be used by clients when formatting addresses for display. */ - pointerSize?: number; }; } @@ -325,8 +323,6 @@ declare module DebugProtocol { supportsVariablePaging?: boolean; /** Client supports the runInTerminal request. */ supportsRunInTerminalRequest?: boolean; - /** Client supports memory references. */ - supportsMemoryReferences?: boolean; } /** Response to 'initialize' request. */ @@ -1051,8 +1047,6 @@ declare module DebugProtocol { The client can use this optional information to present the variables in a paged UI and fetch them in chunks. */ indexedVariables?: number; - /** Memory reference to a location appropriate for this result. For pointer type eval results, this is generally a reference to the memory address contained in the pointer. */ - memoryReference?: string; }; } @@ -1208,66 +1202,6 @@ declare module DebugProtocol { }; } - /** ReadMemory request; value of command field is 'readMemory'. - Reads bytes from memory at the provided location. - */ - export interface ReadMemoryRequest extends Request { - // command: 'readMemory'; - arguments: ReadMemoryArguments; - } - - /** Arguments for 'readMemory' request. */ - export interface ReadMemoryArguments { - /** Memory reference to the base location from which data should be read. */ - memoryReference: string; - /** Optional offset (in bytes) to be applied to the reference location before reading data. Can be negative. */ - offset?: number; - /** Number of bytes to read at the specified location and offset. */ - count: number; - } - - /** Response to 'readMemory' request. */ - export interface ReadMemoryResponse extends Response { - body?: { - /** The address of the first byte of data returned. Treated as a hex value if prefixed with '0x', or as a decimal value otherwise. */ - address: string; - /** The number of unreadable bytes encountered after the last successfully read byte. This can be used to determine the number of bytes that must be skipped before a subsequent 'readMemory' request will succeed. */ - unreadableBytes?: number; - /** The bytes read from memory, encoded using base64. */ - data?: string; - }; - } - - /** Disassemble request; value of command field is 'disassemble'. - Disassembles code stored at the provided location. - */ - export interface DisassembleRequest extends Request { - // command: 'disassemble'; - arguments: DisassembleArguments; - } - - /** Arguments for 'disassemble' request. */ - export interface DisassembleArguments { - /** Memory reference to the base location containing the instructions to disassemble. */ - memoryReference: string; - /** Optional offset (in bytes) to be applied to the reference location before disassembling. Can be negative. */ - offset?: number; - /** Optional offset (in instructions) to be applied after the byte offset (if any) before disassembling. Can be negative. */ - instructionOffset?: number; - /** Number of instructions to disassemble starting at the specified location and offset. An adapter must return exactly this number of instructions - any unavailable instructions should be replaced with an implementation-defined 'invalid instruction' value. */ - instructionCount: number; - /** If true, the adapter should attempt to resolve memory addresses and other values to symbolic names. */ - resolveSymbols?: boolean; - } - - /** Response to 'disassemble' request. */ - export interface DisassembleResponse extends Response { - body?: { - /** The list of disassembled instructions. */ - instructions: DisassembledInstruction[]; - }; - } - /** Information about the capabilities of a debug adapter. */ export interface Capabilities { /** The debug adapter supports the 'configurationDone' request. */ @@ -1324,10 +1258,6 @@ declare module DebugProtocol { supportsTerminateRequest?: boolean; /** The debug adapter supports data breakpoints. */ supportsDataBreakpoints?: boolean; - /** The debug adapter supports the 'readMemory' request. */ - supportsReadMemoryRequest?: boolean; - /** The debug adapter supports the 'disassemble' request. */ - supportsDisassembleRequest?: boolean; } /** An ExceptionBreakpointsFilter is shown in the UI as an option for configuring how exceptions are dealt with. */ @@ -1463,8 +1393,6 @@ declare module DebugProtocol { endLine?: number; /** An optional end column of the range covered by the stack frame. */ endColumn?: number; - /** Optional memory reference for the current instruction pointer in this frame. */ - instructionPointerReference?: string; /** The module associated with this frame, if any. */ moduleId?: number | string; /** An optional hint for how to present this frame in the UI. A value of 'label' can be used to indicate that the frame is an artificial frame that is used as a visual label or separator. A value of 'subtle' can be used to change the appearance of a frame in a 'subtle' way. */ @@ -1473,16 +1401,8 @@ declare module DebugProtocol { /** A Scope is a named container for variables. Optionally a scope can map to a source or a range within a source. */ export interface Scope { - /** Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This string is shown in the UI as is and can be translated. */ + /** Name of the scope such as 'Arguments', 'Locals'. */ name: string; - /** An optional hint for how to present this scope in the UI. If this attribute is missing, the scope is shown with a generic UI. - Values: - 'arguments': Scope contains method arguments. - 'locals': Scope contains local variables. - 'registers': Scope contains registers. Only a single 'registers' scope should be returned from a 'scopes' request. - etc. - */ - presentationHint?: string; /** The variables of this scope can be retrieved by passing the value of variablesReference to the VariablesRequest. */ variablesReference: number; /** The number of named variables in this scope. @@ -1535,8 +1455,6 @@ declare module DebugProtocol { The client can use this optional information to present the children in a paged UI and fetch them in chunks. */ indexedVariables?: number; - /** Optional memory reference for the variable if the variable represents executable code, such as a function pointer. */ - memoryReference?: string; } /** Optional properties of a variable that can be used to determine how to render the variable in the UI. */ @@ -1658,8 +1576,6 @@ declare module DebugProtocol { endLine?: number; /** An optional end column of the range covered by the goto target. */ endColumn?: number; - /** Optional memory reference for the instruction pointer value represented by this target. */ - instructionPointerReference?: string; } /** CompletionItems are the suggestions returned from the CompletionsRequest. */ @@ -1757,27 +1673,5 @@ declare module DebugProtocol { /** Details of the exception contained by this exception, if any. */ innerException?: ExceptionDetails[]; } - - /** Represents a single disassembled instruction. */ - export interface DisassembledInstruction { - /** The address of the instruction. Treated as a hex value if prefixed with '0x', or as a decimal value otherwise. */ - address: string; - /** Optional raw bytes representing the instruction and its operands, in an implementation-defined format. */ - instructionBytes?: string; - /** Text representing the instruction and its operands, in an implementation-defined format. */ - instruction: string; - /** Name of the symbol that correponds with the location of this instruction, if any. */ - symbol?: string; - /** Source location that corresponds to this instruction, if any. Should always be set (if available) on the first instruction returned, but can be omitted afterwards if this instruction maps to the same source file as the previous instruction. */ - location?: Source; - /** The line within the source location that corresponds to this instruction, if any. */ - line?: number; - /** The column within the line that corresponds to this instruction, if any. */ - column?: number; - /** The end line of the range that corresponds to this instruction, if any. */ - endLine?: number; - /** The end column of the range that corresponds to this instruction, if any. */ - endColumn?: number; - } } diff --git a/src/vs/workbench/contrib/debug/common/debugSchemas.ts b/src/vs/workbench/contrib/debug/common/debugSchemas.ts index 27390162b1..34bf295134 100644 --- a/src/vs/workbench/contrib/debug/common/debugSchemas.ts +++ b/src/vs/workbench/contrib/debug/common/debugSchemas.ts @@ -47,7 +47,7 @@ export const debuggersExtPoint = extensionsRegistry.ExtensionsRegistry.registerE type: 'array' }, variables: { - description: nls.localize('vscode.extension.contributes.debuggers.variables', "Mapping from interactive variables (e.g. ${action.pickProcess}) in `launch.json` to a command."), + description: nls.localize('vscode.extension.contributes.debuggers.variables', "Mapping from interactive variables (e.g ${action.pickProcess}) in `launch.json` to a command."), type: 'object' }, initialConfigurations: { diff --git a/src/vs/workbench/contrib/debug/common/debugSource.ts b/src/vs/workbench/contrib/debug/common/debugSource.ts index fe4fd729d4..bf53f2ca90 100644 --- a/src/vs/workbench/contrib/debug/common/debugSource.ts +++ b/src/vs/workbench/contrib/debug/common/debugSource.ts @@ -12,7 +12,6 @@ import { IRange } from 'vs/editor/common/core/range'; import { IEditorService, SIDE_GROUP, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { Schemas } from 'vs/base/common/network'; import { isUri } from 'vs/workbench/contrib/debug/common/debugUtils'; -import { ITextEditor } from 'vs/workbench/common/editor'; export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Source"); @@ -26,6 +25,7 @@ export const UNKNOWN_SOURCE_LABEL = nls.localize('unknownSource', "Unknown Sourc * | | | | * scheme source.path session id source.reference * + * the arbitrary_path and the session id are encoded with 'encodeURIComponent' * */ @@ -48,11 +48,7 @@ export class Source { } if (typeof this.raw.sourceReference === 'number' && this.raw.sourceReference > 0) { - this.uri = uri.from({ - scheme: DEBUG_SCHEME, - path, - query: `session=${sessionId}&ref=${this.raw.sourceReference}` - }); + this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}&ref=${this.raw.sourceReference}`); } else { if (isUri(path)) { // path looks like a uri this.uri = uri.parse(path); @@ -63,11 +59,7 @@ export class Source { } else { // path is relative: since VS Code cannot deal with this by itself // create a debug url that will result in a DAP 'source' request when the url is resolved. - this.uri = uri.from({ - scheme: DEBUG_SCHEME, - path, - query: `session=${sessionId}` - }); + this.uri = uri.parse(`${DEBUG_SCHEME}:${encodeURIComponent(path)}?session=${encodeURIComponent(sessionId)}`); } } } @@ -93,13 +85,14 @@ export class Source { return this.uri.scheme === DEBUG_SCHEME; } - openInEditor(editorService: IEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { + openInEditor(editorService: IEditorService, selection: IRange, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { return !this.available ? Promise.resolve(null) : editorService.openEditor({ resource: this.uri, description: this.origin, options: { preserveFocus, selection, + revealIfVisible: true, revealIfOpened: true, revealInCenterIfOutsideViewport: true, pinned: pinned || (!preserveFocus && !this.inMemory) @@ -125,7 +118,7 @@ export class Source { if (pair.length === 2) { switch (pair[0]) { case 'session': - sessionId = pair[1]; + sessionId = decodeURIComponent(pair[1]); break; case 'ref': sourceReference = parseInt(pair[1]); diff --git a/src/vs/workbench/contrib/debug/electron-browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/electron-browser/debug.contribution.ts index a59072a40a..78a2a0171f 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debug.contribution.ts @@ -15,6 +15,8 @@ import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'v import { IWorkbenchActionRegistry, Extensions as WorkbenchActionRegistryExtensions } from 'vs/workbench/common/actions'; import { ShowViewletAction, Extensions as ViewletExtensions, ViewletRegistry, ViewletDescriptor } from 'vs/workbench/browser/viewlet'; import { TogglePanelAction, Extensions as PanelExtensions, PanelRegistry, PanelDescriptor } from 'vs/workbench/browser/panel'; +import { StatusbarItemDescriptor, IStatusbarRegistry, Extensions as StatusExtensions } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { BreakpointsView } from 'vs/workbench/contrib/debug/browser/breakpointsView'; import { CallStackView } from 'vs/workbench/contrib/debug/browser/callStackView'; import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; @@ -38,7 +40,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { URI } from 'vs/base/common/uri'; import { DebugViewlet } from 'vs/workbench/contrib/debug/browser/debugViewlet'; import { DebugQuickOpenHandler } from 'vs/workbench/contrib/debug/browser/debugQuickOpen'; -import { DebugStatusContribution } from 'vs/workbench/contrib/debug/browser/debugStatus'; +import { DebugStatus } from 'vs/workbench/contrib/debug/browser/debugStatus'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { launchSchemaId } from 'vs/workbench/services/configuration/common/configuration'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; @@ -257,7 +259,8 @@ configurationRegistry.registerConfiguration({ }); // Register Debug Status -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugStatusContribution, LifecyclePhase.Eventually); +const statusBar = Registry.as(StatusExtensions.Statusbar); +statusBar.registerStatusbarItem(new StatusbarItemDescriptor(DebugStatus, StatusbarAlignment.LEFT, 30 /* Low Priority */)); // Debug toolbar @@ -534,9 +537,7 @@ if (isMacintosh) { const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr, icon: string) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { - id, - title, - iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/electron-browser/media/${icon}`)) } + id, title, iconLocation: { dark: URI.parse(require.toUrl(`vs/workbench/contrib/debug/electron-browser/media/${icon}`)) } }, when, group: '9_debug', @@ -548,9 +549,9 @@ if (isMacintosh) { registerTouchBarEntry(RunAction.ID, RunAction.LABEL, 1, CONTEXT_IN_DEBUG_MODE.toNegated(), 'continue-without-debugging-tb.png'); registerTouchBarEntry(CONTINUE_ID, continueLabel, 0, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'continue-tb.png'); registerTouchBarEntry(PAUSE_ID, pauseLabel, 1, ContextKeyExpr.and(CONTEXT_IN_DEBUG_MODE, ContextKeyExpr.notEquals('debugState', 'stopped')), 'pause-tb.png'); - registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_IN_DEBUG_MODE, 'stepover-tb.png'); - registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_IN_DEBUG_MODE, 'stepinto-tb.png'); - registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_IN_DEBUG_MODE, 'stepout-tb.png'); + registerTouchBarEntry(STEP_OVER_ID, stepOverLabel, 2, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepover-tb.png'); + registerTouchBarEntry(STEP_INTO_ID, stepIntoLabel, 3, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepinto-tb.png'); + registerTouchBarEntry(STEP_OUT_ID, stepOutLabel, 4, CONTEXT_DEBUG_STATE.isEqualTo('stopped'), 'stepout-tb.png'); registerTouchBarEntry(RESTART_SESSION_ID, restartLabel, 5, CONTEXT_IN_DEBUG_MODE, 'restart-tb.png'); registerTouchBarEntry(STOP_ID, stopLabel, 6, CONTEXT_IN_DEBUG_MODE, 'stop-tb.png'); } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts index fdc8e29d17..58f4edafec 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugConfigurationManager.ts @@ -52,7 +52,7 @@ export class ConfigurationManager implements IConfigurationManager { private _onDidSelectConfigurationName = new Emitter(); private configProviders: IDebugConfigurationProvider[]; private adapterDescriptorFactories: IDebugAdapterDescriptorFactory[]; - private debugAdapterFactories = new Map(); + private debugAdapterFactories: Map; private terminalLauncher: ITerminalLauncher; private debugConfigurationTypeContext: IContextKey; @@ -78,6 +78,7 @@ export class ConfigurationManager implements IConfigurationManager { const previousSelectedRoot = this.storageService.get(DEBUG_SELECTED_ROOT, StorageScope.WORKSPACE); const previousSelectedLaunch = this.launches.filter(l => l.uri.toString() === previousSelectedRoot).pop(); this.debugConfigurationTypeContext = CONTEXT_DEBUG_CONFIGURATION_TYPE.bindTo(contextKeyService); + this.debugAdapterFactories = new Map(); if (previousSelectedLaunch) { this.selectConfiguration(previousSelectedLaunch, this.storageService.get(DEBUG_SELECTED_CONFIG_NAME_KEY, StorageScope.WORKSPACE)); } diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts index 5d7fb630ee..d3ce1ebe6b 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugService.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugService.ts @@ -46,7 +46,6 @@ import { isExtensionHostDebugging } from 'vs/workbench/contrib/debug/common/debu import { isErrorWithActions, createErrorWithActions } from 'vs/base/common/errorsWithActions'; import { RunOnceScheduler } from 'vs/base/common/async'; import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; const DEBUG_BREAKPOINTS_KEY = 'debug.breakpoint'; const DEBUG_BREAKPOINTS_ACTIVATED_KEY = 'debug.breakpointactivated'; @@ -432,6 +431,9 @@ export class DebugService implements IDebugService { return this.launchOrAttachToSession(session).then(() => { + // since the initialized response has arrived announce the new Session (including extensions) + this._onDidNewSession.fire(session); + const internalConsoleOptions = session.configuration.internalConsoleOptions || this.configurationService.getValue('debug').internalConsoleOptions; if (internalConsoleOptions === 'openOnSessionStart' || (this.viewModel.firstSessionStart && internalConsoleOptions === 'openOnFirstSessionStart')) { this.panelService.openPanel(REPL_ID, false); @@ -445,9 +447,6 @@ export class DebugService implements IDebugService { this.viewModel.setMultiSessionView(true); } - // since the initialized response has arrived announce the new Session (including extensions) - this._onDidNewSession.fire(session); - return this.telemetryDebugSessionStart(root, session.configuration.type); }).then(() => true, (error: Error | string) => { @@ -659,9 +658,9 @@ export class DebugService implements IDebugService { return Promise.resolve(config); } - private showError(message: string, errorActions: ReadonlyArray = []): Promise { + private showError(message: string, actions: IAction[] = []): Promise { const configureAction = this.instantiationService.createInstance(debugactions.ConfigureAction, debugactions.ConfigureAction.ID, debugactions.ConfigureAction.LABEL); - const actions = [...errorActions, configureAction]; + actions.push(configureAction); return this.dialogService.show(severity.Error, message, actions.map(a => a.label).concat(nls.localize('cancel', "Cancel")), { cancelId: actions.length }).then(choice => { if (choice < actions.length) { return actions[choice].run(); @@ -790,15 +789,8 @@ export class DebugService implements IDebugService { } if (stackFrame) { - stackFrame.openInEditor(this.editorService, true).then(editor => { - if (editor) { - const control = editor.getControl(); - if (stackFrame && isCodeEditor(control) && control.hasModel()) { - const lineContent = control.getModel().getLineContent(stackFrame.range.startLineNumber); - aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2} {3}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber, lineContent)); - } - } - }); + stackFrame.openInEditor(this.editorService, true); + aria.alert(nls.localize('debuggingPaused', "Debugging paused {0}, {1} {2}", thread && thread.stoppedDetails ? `, reason ${thread.stoppedDetails.reason}` : '', stackFrame.source ? stackFrame.source.name : '', stackFrame.range.startLineNumber)); } if (session) { this.debugType.set(session.configuration.type); @@ -854,7 +846,7 @@ export class DebugService implements IDebugService { return this.sendBreakpoints(uri).then(() => breakpoints); } - updateBreakpoints(uri: uri, data: Map, sendOnResourceSaved: boolean): void { + updateBreakpoints(uri: uri, data: { [id: string]: DebugProtocol.Breakpoint }, sendOnResourceSaved: boolean): void { this.model.updateBreakpoints(data); if (sendOnResourceSaved) { this.breakpointsToSendOnResourceSaved.add(uri.toString()); diff --git a/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts b/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts index 96279c3b9e..52790f4730 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/debugSession.ts @@ -282,14 +282,14 @@ export class DebugSession implements IDebugSession { return this.raw.setBreakpoints({ source: rawSource, - lines: breakpointsToSend.map(bp => bp.sessionAgnosticData.lineNumber), - breakpoints: breakpointsToSend.map(bp => ({ line: bp.sessionAgnosticData.lineNumber, column: bp.sessionAgnosticData.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })), + lines: breakpointsToSend.map(bp => bp.lineNumber), + breakpoints: breakpointsToSend.map(bp => ({ line: bp.lineNumber, column: bp.column, condition: bp.condition, hitCondition: bp.hitCondition, logMessage: bp.logMessage })), sourceModified }).then(response => { if (response && response.body) { - const data = new Map(); + const data: { [id: string]: DebugProtocol.Breakpoint } = Object.create(null); for (let i = 0; i < breakpointsToSend.length; i++) { - data.set(breakpointsToSend[i].getId(), response.body.breakpoints[i]); + data[breakpointsToSend[i].getId()] = response.body.breakpoints[i]; } this.model.setBreakpointSessionData(this.getId(), data); @@ -302,9 +302,9 @@ export class DebugSession implements IDebugSession { if (this.raw.readyForBreakpoints) { return this.raw.setFunctionBreakpoints({ breakpoints: fbpts }).then(response => { if (response && response.body) { - const data = new Map(); + const data: { [id: string]: DebugProtocol.Breakpoint } = Object.create(null); for (let i = 0; i < fbpts.length; i++) { - data.set(fbpts[i].getId(), response.body.breakpoints[i]); + data[fbpts[i].getId()] = response.body.breakpoints[i]; } this.model.setBreakpointSessionData(this.getId(), data); } @@ -753,8 +753,7 @@ export class DebugSession implements IDebugSession { lineNumber: event.body.breakpoint.line, }], false); if (bps.length === 1) { - const data = new Map([[bps[0].getId(), event.body.breakpoint]]); - this.model.setBreakpointSessionData(this.getId(), data); + this.model.setBreakpointSessionData(this.getId(), { [bps[0].getId()]: event.body.breakpoint }); } } @@ -772,12 +771,10 @@ export class DebugSession implements IDebugSession { if (!breakpoint.column) { event.body.breakpoint.column = undefined; } - const data = new Map([[breakpoint.getId(), event.body.breakpoint]]); - this.model.setBreakpointSessionData(this.getId(), data); + this.model.setBreakpointSessionData(this.getId(), { [breakpoint.getId()]: event.body.breakpoint }); } if (functionBreakpoint) { - const data = new Map([[functionBreakpoint.getId(), event.body.breakpoint]]); - this.model.setBreakpointSessionData(this.getId(), data); + this.model.setBreakpointSessionData(this.getId(), { [functionBreakpoint.getId()]: event.body.breakpoint }); } } })); diff --git a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts index efd61225ab..02c7022392 100644 --- a/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/electron-browser/rawDebugSession.ts @@ -487,7 +487,7 @@ export class RawDebugSession { } } - private async dispatchRequest(request: DebugProtocol.Request, dbgr: IDebugger): Promise { + private dispatchRequest(request: DebugProtocol.Request, dbgr: IDebugger): void { const response: DebugProtocol.Response = { type: 'response', @@ -528,7 +528,7 @@ export class RawDebugSession { break; case 'handshake': try { - const vsda = await import('vsda'); + const vsda = require.__$__nodeRequire('vsda'); const obj = new vsda.signer(); const sig = obj.sign(request.arguments.value); response.body = { diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index 81fff85edf..46d052be42 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -348,10 +348,8 @@ export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments quote = (s: string) => { s = s.replace(/\'/g, '\'\''); - if (s.length > 0 && s.charAt(s.length - 1) === '\\') { - return `'${s}\\'`; - } return `'${s}'`; + //return s.indexOf(' ') >= 0 || s.indexOf('\'') >= 0 || s.indexOf('"') >= 0 ? `'${s}'` : s; }; if (args.cwd) { @@ -409,8 +407,8 @@ export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments case ShellType.bash: quote = (s: string) => { - s = s.replace(/([\"\\])/g, '\\$1'); - return s.indexOf(' ') >= 0 ? `"${s}"` : s; + s = s.replace(/\"/g, '\\"'); + return (s.indexOf(' ') >= 0 || s.indexOf('\\') >= 0) ? `"${s}"` : s; }; const hardQuote = (s: string) => { diff --git a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts index f83e631ca8..804611228c 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugANSIHandling.test.ts @@ -11,9 +11,6 @@ import { TestInstantiationService } from 'vs/platform/instantiation/test/common/ import { workbenchInstantiationService } from 'vs/workbench/test/workbenchTestServices'; import { LinkDetector } from 'vs/workbench/contrib/debug/browser/linkDetector'; import { Color, RGBA } from 'vs/base/common/color'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { TestThemeService, TestTheme } from 'vs/platform/theme/test/common/testThemeService'; -import { ansiColorMap } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; suite('Debug - ANSI Handling', () => { test('appendStylizedStringToContainer', () => { diff --git a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts index 71077188b2..3b5db8c9c6 100644 --- a/src/vs/workbench/contrib/debug/test/common/mockDebug.ts +++ b/src/vs/workbench/contrib/debug/test/common/mockDebug.ts @@ -51,7 +51,7 @@ export class MockDebugService implements IDebugService { throw new Error('not implemented'); } - public updateBreakpoints(uri: uri, data: Map, sendOnResourceSaved: boolean): void { } + public updateBreakpoints(uri: uri, data: { [id: string]: IBreakpointUpdateData }, sendOnResourceSaved: boolean): void { } public enableOrDisableBreakpoints(enabled: boolean): Promise { throw new Error('not implemented'); diff --git a/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts index 7fe5c3d54e..0cf96e3e64 100644 --- a/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/electron-browser/debugModel.test.ts @@ -12,7 +12,6 @@ import { MockRawSession } from 'vs/workbench/contrib/debug/test/common/mockDebug import { Source } from 'vs/workbench/contrib/debug/common/debugSource'; import { DebugSession } from 'vs/workbench/contrib/debug/electron-browser/debugSession'; import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; -import { IBreakpointUpdateData } from 'vs/workbench/contrib/debug/common/debug'; function createMockSession(model: DebugModel, name = 'mockSession', parentSession?: DebugSession | undefined): DebugSession { return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); @@ -64,8 +63,8 @@ suite('Debug - Model', () => { assert.equal(model.getBreakpoints().length, 5); const bp = model.getBreakpoints()[0]; - const update = new Map(); - update.set(bp.getId(), { lineNumber: 100 }); + const update: any = {}; + update[bp.getId()] = { lineNumber: 100 }; model.updateBreakpoints(update); assert.equal(bp.lineNumber, 100); diff --git a/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts b/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts index bae5a5c968..28ee86712a 100644 --- a/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts +++ b/src/vs/workbench/contrib/experiments/electron-browser/experimentalPrompt.ts @@ -9,10 +9,11 @@ import { IExperimentService, IExperiment, ExperimentActionType, IExperimentActio import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionsViewlet } from 'vs/workbench/contrib/extensions/common/extensions'; import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { language } from 'vs/base/common/platform'; export class ExperimentalPrompts extends Disposable implements IWorkbenchContribution { + private _disposables: IDisposable[] = []; constructor( @IExperimentService private readonly experimentService: IExperimentService, @@ -22,11 +23,11 @@ export class ExperimentalPrompts extends Disposable implements IWorkbenchContrib ) { super(); - this._register(this.experimentService.onExperimentEnabled(e => { + this.experimentService.onExperimentEnabled(e => { if (e.action && e.action.type === ExperimentActionType.Prompt && e.state === ExperimentState.Run) { this.showExperimentalPrompts(e); } - }, this)); + }, this, this._disposables); } private showExperimentalPrompts(experiment: IExperiment): void { @@ -90,6 +91,10 @@ export class ExperimentalPrompts extends Disposable implements IWorkbenchContrib }); } + dispose() { + this._disposables = dispose(this._disposables); + } + static getLocalizedText(text: string | { [key: string]: string }, displayLanguage: string): string { if (typeof text === 'string') { return text; diff --git a/src/vs/workbench/contrib/experiments/node/experimentService.ts b/src/vs/workbench/contrib/experiments/node/experimentService.ts index ab2b50e18a..d4fc6203c9 100644 --- a/src/vs/workbench/contrib/experiments/node/experimentService.ts +++ b/src/vs/workbench/contrib/experiments/node/experimentService.ts @@ -115,9 +115,9 @@ export class ExperimentService extends Disposable implements IExperimentService private _curatedMapping = Object.create(null); private _disposables: IDisposable[] = []; - private readonly _onExperimentEnabled = this._register(new Emitter()); - onExperimentEnabled: Event = this._onExperimentEnabled.event; + private readonly _onExperimentEnabled = new Emitter(); + onExperimentEnabled: Event = this._onExperimentEnabled.event; constructor( @IStorageService private readonly storageService: IStorageService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts index 23c082d8ed..7b6d584759 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewer.ts @@ -255,7 +255,7 @@ export class ExtensionData implements IExtensionData { toQuery.push(id); } } - const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: toQuery, pageSize: toQuery.length }, CancellationToken.None); + const galleryResult = await this.extensionsWorkbenchService.queryGallery({ names: this.childrenExtensionIds, pageSize: this.childrenExtensionIds.length }, CancellationToken.None); result.push(...galleryResult.firstPage); return result.map(extension => new ExtensionData(extension, this, this.getChildrenExtensionIds, this.extensionsWorkbenchService)); } diff --git a/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts b/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts index d227d18ba2..d33787e72c 100644 --- a/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts +++ b/src/vs/workbench/contrib/extensions/common/extensionsUtils.ts @@ -7,7 +7,7 @@ import * as arrays from 'vs/base/common/arrays'; import { localize } from 'vs/nls'; import { Event } from 'vs/base/common/event'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService, IExtensionTipsService, IExtensionIdentifier, EnablementState, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; @@ -22,7 +22,9 @@ export interface IExtensionStatus { globallyEnabled: boolean; } -export class KeymapExtensions extends Disposable implements IWorkbenchContribution { +export class KeymapExtensions implements IWorkbenchContribution { + + private disposables: IDisposable[] = []; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @@ -32,12 +34,13 @@ export class KeymapExtensions extends Disposable implements IWorkbenchContributi @INotificationService private readonly notificationService: INotificationService, @ITelemetryService private readonly telemetryService: ITelemetryService, ) { - super(); - this._register(lifecycleService.onShutdown(() => this.dispose())); - this._register(instantiationService.invokeFunction(onExtensionChanged)((identifiers => { - Promise.all(identifiers.map(identifier => this.checkForOtherKeymaps(identifier))) - .then(undefined, onUnexpectedError); - }))); + this.disposables.push( + lifecycleService.onShutdown(() => this.dispose()), + instantiationService.invokeFunction(onExtensionChanged)((identifiers => { + Promise.all(identifiers.map(identifier => this.checkForOtherKeymaps(identifier))) + .then(undefined, onUnexpectedError); + })) + ); } private checkForOtherKeymaps(extensionIdentifier: IExtensionIdentifier): Promise { @@ -84,6 +87,10 @@ export class KeymapExtensions extends Disposable implements IWorkbenchContributi }] ); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export function onExtensionChanged(accessor: ServicesAccessor): Event { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts index 68151f1f27..2ea647db3a 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionEditor.ts @@ -13,7 +13,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { Cache, CacheResult } from 'vs/base/common/cache'; import { Action } from 'vs/base/common/actions'; import { isPromiseCanceledError } from 'vs/base/common/errors'; -import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { domEvent } from 'vs/base/browser/event'; import { append, $, addClass, removeClass, finalHandler, join, toggleClass, hide, show } from 'vs/base/browser/dom'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; @@ -89,9 +89,9 @@ function removeEmbeddedSVGs(documentContent: string): string { return newDocument.documentElement.outerHTML; } -class NavBar extends Disposable { +class NavBar { - private _onChange = this._register(new Emitter<{ id: string | null, focus: boolean }>()); + private _onChange = new Emitter<{ id: string | null, focus: boolean }>(); get onChange(): Event<{ id: string | null, focus: boolean }> { return this._onChange.event; } private currentId: string | null = null; @@ -99,10 +99,9 @@ class NavBar extends Disposable { private actionbar: ActionBar; constructor(container: HTMLElement) { - super(); const element = append(container, $('.navbar')); this.actions = []; - this.actionbar = this._register(new ActionBar(element, { animated: false })); + this.actionbar = new ActionBar(element, { animated: false }); } push(id: string, label: string, tooltip: string): void { @@ -133,6 +132,10 @@ class NavBar extends Disposable { this.actions.forEach(a => a.enabled = a.id !== id); return Promise.resolve(undefined); } + + dispose(): void { + dispose(this.actionbar); + } } const NavbarSection = { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts index 597733b167..f9c4ebac54 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionProfileService.ts @@ -5,11 +5,14 @@ import * as nls from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; -import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionHostProfile, ProfileSession, IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { append, $, addDisposableListener } from 'vs/base/browser/dom'; +import { IStatusbarRegistry, StatusbarItemDescriptor, Extensions, IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; +import { Registry } from 'vs/platform/registry/common/platform'; import { IExtensionHostProfileService, ProfileSessionState } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IWindowsService } from 'vs/platform/windows/common/windows'; @@ -19,11 +22,10 @@ import product from 'vs/platform/product/node/product'; import { RuntimeExtensionsInput } from 'vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsInput'; import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { ExtensionHostProfiler } from 'vs/workbench/services/extensions/electron-browser/extensionHostProfiler'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; export class ExtensionHostProfileService extends Disposable implements IExtensionHostProfileService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; private readonly _onDidChangeState: Emitter = this._register(new Emitter()); public readonly onDidChangeState: Event = this._onDidChangeState.event; @@ -36,9 +38,6 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio private _profileSession: ProfileSession | null; private _state: ProfileSessionState; - private profilingStatusBarIndicator: IStatusbarEntryAccessor | undefined; - private profilingStatusBarIndicatorLabelUpdater: IDisposable | undefined; - public get state() { return this._state; } public get lastProfile() { return this._profile; } @@ -47,18 +46,12 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio @IEditorService private readonly _editorService: IEditorService, @IInstantiationService private readonly _instantiationService: IInstantiationService, @IWindowsService private readonly _windowsService: IWindowsService, - @IDialogService private readonly _dialogService: IDialogService, - @IStatusbarService private readonly _statusbarService: IStatusbarService, + @IDialogService private readonly _dialogService: IDialogService ) { super(); this._profile = null; this._profileSession = null; this._setState(ProfileSessionState.None); - - CommandsRegistry.registerCommand('workbench.action.extensionHostProfilder.stop', () => { - this.stopProfiling(); - this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true }); - }); } private _setState(state: ProfileSessionState): void { @@ -68,48 +61,17 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio this._state = state; if (this._state === ProfileSessionState.Running) { - this.updateProfilingStatusBarIndicator(true); + ProfileExtHostStatusbarItem.instance.show(() => { + this.stopProfiling(); + this._editorService.openEditor(this._instantiationService.createInstance(RuntimeExtensionsInput), { revealIfOpened: true }); + }); } else if (this._state === ProfileSessionState.Stopping) { - this.updateProfilingStatusBarIndicator(false); + ProfileExtHostStatusbarItem.instance.hide(); } this._onDidChangeState.fire(undefined); } - private updateProfilingStatusBarIndicator(visible: boolean): void { - if (this.profilingStatusBarIndicatorLabelUpdater) { - this.profilingStatusBarIndicatorLabelUpdater.dispose(); - this.profilingStatusBarIndicatorLabelUpdater = undefined; - } - - if (visible) { - const indicator: IStatusbarEntry = { - text: nls.localize('profilingExtensionHost', "$(sync~spin) Profiling Extension Host"), - tooltip: nls.localize('selectAndStartDebug', "Click to stop profiling."), - command: 'workbench.action.extensionHostProfilder.stop' - }; - - const timeStarted = Date.now(); - const handle = setInterval(() => { - if (this.profilingStatusBarIndicator) { - this.profilingStatusBarIndicator.update({ ...indicator, text: nls.localize('profilingExtensionHostTime', "$(sync~spin) Profiling Extension Host ({0} sec)", Math.round((new Date().getTime() - timeStarted) / 1000)), }); - } - }, 1000); - this.profilingStatusBarIndicatorLabelUpdater = toDisposable(() => clearInterval(handle)); - - if (!this.profilingStatusBarIndicator) { - this.profilingStatusBarIndicator = this._statusbarService.addEntry(indicator, 'status.profiler', nls.localize('status.profiler', "Extension Profiler"), StatusbarAlignment.RIGHT); - } else { - this.profilingStatusBarIndicator.update(indicator); - } - } else { - if (this.profilingStatusBarIndicator) { - this.profilingStatusBarIndicator.dispose(); - this.profilingStatusBarIndicator = undefined; - } - } - } - public startProfiling(): Promise | null { if (this._state !== ProfileSessionState.None) { return null; @@ -172,3 +134,76 @@ export class ExtensionHostProfileService extends Disposable implements IExtensio } } + +export class ProfileExtHostStatusbarItem implements IStatusbarItem { + + public static instance: ProfileExtHostStatusbarItem; + + private toDispose: IDisposable[]; + private statusBarItem: HTMLElement; + private label: HTMLElement; + private timeStarted: number; + private labelUpdater: any; + private clickHandler: (() => void) | null; + + constructor() { + ProfileExtHostStatusbarItem.instance = this; + this.toDispose = []; + this.timeStarted = 0; + } + + public show(clickHandler: () => void) { + this.clickHandler = clickHandler; + if (this.timeStarted === 0) { + this.timeStarted = new Date().getTime(); + this.statusBarItem.hidden = false; + this.labelUpdater = setInterval(() => { + this.updateLabel(); + }, 1000); + this.updateLabel(); + } + } + + public hide() { + this.clickHandler = null; + this.statusBarItem.hidden = true; + this.timeStarted = 0; + clearInterval(this.labelUpdater); + this.labelUpdater = null; + } + + public render(container: HTMLElement): IDisposable { + if (!this.statusBarItem && container) { + this.statusBarItem = append(container, $('.profileExtHost-statusbar-item')); + this.toDispose.push(addDisposableListener(this.statusBarItem, 'click', () => { + if (this.clickHandler) { + this.clickHandler(); + } + })); + this.statusBarItem.title = nls.localize('selectAndStartDebug', "Click to stop profiling."); + const a = append(this.statusBarItem, $('a')); + append(a, $('.icon')); + this.label = append(a, $('span.label')); + this.updateLabel(); + this.statusBarItem.hidden = true; + } + return this; + } + + private updateLabel() { + let label = 'Profiling Extension Host'; + if (this.timeStarted > 0) { + let secondsRecoreded = (new Date().getTime() - this.timeStarted) / 1000; + label = `Profiling Extension Host (${Math.round(secondsRecoreded)} sec)`; + } + this.label.textContent = label; + } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } +} + +Registry.as(Extensions.Statusbar).registerStatusbarItem( + new StatusbarItemDescriptor(ProfileExtHostStatusbarItem, StatusbarAlignment.RIGHT) +); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index 0cb5f57fdd..c3e300e55f 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -11,7 +11,7 @@ import { match } from 'vs/base/common/glob'; import * as json from 'vs/base/common/json'; import { IExtensionManagementService, IExtensionGalleryService, IExtensionTipsService, ExtensionRecommendationReason, EXTENSION_IDENTIFIER_PATTERN, - IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource, InstallOperation, ILocalExtension + IExtensionsConfigContent, RecommendationChangeNotification, IExtensionRecommendation, ExtensionRecommendationSource, InstallOperation } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IModelService } from 'vs/editor/common/services/modelService'; import { ITextModel } from 'vs/editor/common/model'; @@ -90,7 +90,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe public loadWorkspaceConfigPromise: Promise; private proactiveRecommendationsFetched: boolean = false; - private readonly _onRecommendationChange = this._register(new Emitter()); + private readonly _onRecommendationChange = new Emitter(); onRecommendationChange: Event = this._onRecommendationChange.event; private sessionSeed: number; @@ -597,6 +597,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe * or prompt to search the marketplace if it has extensions that can support the file type */ private promptFiletypeBasedRecommendations(model: ITextModel): void { + let hasSuggestion = false; + const uri = model.uri; if (!uri || !this.fileService.canHandleResource(uri)) { return; @@ -610,244 +612,231 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe processedFileExtensions.push(fileExtension); } - // re-schedule this bit of the operation to be off the critical path - in case glob-match is slow - setImmediate(async () => { - const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); - if (await this.promptRecommendedExtensionForFileType(model, installed)) { - return; - } + // re-schedule this bit of the operation to be off + // the critical path - in case glob-match is slow + setImmediate(() => { - if (fileExtension) { - fileExtension = fileExtension.substr(1); // Strip the dot - } - if (!fileExtension) { - return; - } - - await this.extensionService.whenInstalledExtensionsRegistered(); - const mimeTypes = await guessMimeTypes(uri.fsPath); - if (mimeTypes.length !== 1 || mimeTypes[0] !== MIME_UNKNOWN) { - return; - } - - this.promptRecommendedExtensionForFileExtension(fileExtension, installed); - }); - } - - private async promptRecommendedExtensionForFileType(model: ITextModel, installed: ILocalExtension[]): Promise { - let recommendationsToSuggest: string[] = []; - const now = Date.now(); - forEach(this._availableRecommendations, entry => { - let { key: pattern, value: ids } = entry; - if (match(pattern, model.uri.path)) { - for (let id of ids) { - if (caseInsensitiveGet(product.extensionImportantTips, id)) { - recommendationsToSuggest.push(id); - } - const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] }; - filedBasedRecommendation.recommendedTime = now; - if (!filedBasedRecommendation.sources.some(s => s instanceof URI && s.toString() === model.uri.toString())) { - filedBasedRecommendation.sources.push(model.uri); - } - this._fileBasedRecommendations[id.toLowerCase()] = filedBasedRecommendation; - } - } - }); - - this.storageService.store( - 'extensionsAssistant/recommendations', - JSON.stringify(Object.keys(this._fileBasedRecommendations).reduce((result, key) => { result[key] = this._fileBasedRecommendations[key].recommendedTime; return result; }, {})), - StorageScope.GLOBAL - ); - - const config = this.configurationService.getValue(ConfigurationKey); - if (config.ignoreRecommendations || config.showRecommendationsOnlyOnDemand) { - return false; - } - - const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); - recommendationsToSuggest = recommendationsToSuggest.filter(id => { - if (importantRecommendationsIgnoreList.indexOf(id) !== -1) { - return false; - } - if (!this.isExtensionAllowedToBeRecommended(id)) { - return false; - } - if (installedExtensionsIds.has(id.toLowerCase())) { - return false; - } - return true; - }); - - if (recommendationsToSuggest.length === 0) { - return false; - } - - const id = recommendationsToSuggest[0]; - const entry = caseInsensitiveGet(product.extensionImportantTips, id); - if (!entry) { - return false; - } - const name = entry['name']; - - let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); - // Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364 - if (id === 'vscjava.vscode-java-pack') { - message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); - } - - const setIgnoreRecommendationsConfig = (configVal: boolean) => { - this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); - if (configVal) { - const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; - this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); - } - }; - - this.notificationService.prompt(Severity.Info, message, - [{ - label: localize('install', 'Install'), - run: () => { - /* __GDPR__ - "extensionRecommendations:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name }); - this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run(); - } - }, { - label: localize('showRecommendations', "Show Recommendations"), - run: () => { - /* __GDPR__ - "extensionRecommendations:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + let recommendationsToSuggest: string[] = []; + const now = Date.now(); + forEach(this._availableRecommendations, entry => { + let { key: pattern, value: ids } = entry; + if (match(pattern, uri.path)) { + for (let id of ids) { + if (caseInsensitiveGet(product.extensionImportantTips, id)) { + recommendationsToSuggest.push(id); } - */ - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name }); - - const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); - recommendationsAction.run(); - recommendationsAction.dispose(); - } - }, { - label: choiceNever, - isSecondary: true, - run: () => { - importantRecommendationsIgnoreList.push(id); - this.storageService.store( - 'extensionsAssistant/importantRecommendationsIgnore', - JSON.stringify(importantRecommendationsIgnoreList), - StorageScope.GLOBAL - ); - /* __GDPR__ - "extensionRecommendations:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + const filedBasedRecommendation = this._fileBasedRecommendations[id.toLowerCase()] || { recommendedTime: now, sources: [] }; + filedBasedRecommendation.recommendedTime = now; + if (!filedBasedRecommendation.sources.some(s => s instanceof URI && s.toString() === uri.toString())) { + filedBasedRecommendation.sources.push(uri); } - */ - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); + this._fileBasedRecommendations[id.toLowerCase()] = filedBasedRecommendation; + } + } + }); + + this.storageService.store( + 'extensionsAssistant/recommendations', + JSON.stringify(Object.keys(this._fileBasedRecommendations).reduce((result, key) => { result[key] = this._fileBasedRecommendations[key].recommendedTime; return result; }, {})), + StorageScope.GLOBAL + ); + + const config = this.configurationService.getValue(ConfigurationKey); + if (config.ignoreRecommendations || config.showRecommendationsOnlyOnDemand) { + return; + } + + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + recommendationsToSuggest = recommendationsToSuggest.filter(id => importantRecommendationsIgnoreList.indexOf(id) === -1 && this.isExtensionAllowedToBeRecommended(id)); + + const importantTipsPromise = recommendationsToSuggest.length === 0 ? Promise.resolve(null) : this.extensionWorkbenchService.queryLocal().then(local => { + const localExtensions = local.map(e => e.identifier); + recommendationsToSuggest = recommendationsToSuggest.filter(id => localExtensions.every(local => !areSameExtensions(local, { id }))); + if (!recommendationsToSuggest.length) { + return; + } + const id = recommendationsToSuggest[0]; + const entry = caseInsensitiveGet(product.extensionImportantTips, id); + if (!entry) { + return; + } + const name = entry['name']; + + // Indicates we have a suggested extension via the whitelist + hasSuggestion = true; + + let message = localize('reallyRecommended2', "The '{0}' extension is recommended for this file type.", name); + // Temporary fix for the only extension pack we recommend. See https://github.com/Microsoft/vscode/issues/35364 + if (id === 'vscjava.vscode-java-pack') { + message = localize('reallyRecommendedExtensionPack', "The '{0}' extension pack is recommended for this file type.", name); + } + + const setIgnoreRecommendationsConfig = (configVal: boolean) => { + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); + if (configVal) { + const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); + } + }; + + this.notificationService.prompt(Severity.Info, message, + [{ + label: localize('install', 'Install'), + run: () => { + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run(); + } + }, { + label: localize('showRecommendations', "Show Recommendations"), + run: () => { + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'show', extensionId: name }); + + const recommendationsAction = this.instantiationService.createInstance(ShowRecommendedExtensionsAction, ShowRecommendedExtensionsAction.ID, localize('showRecommendations', "Show Recommendations")); + recommendationsAction.run(); + recommendationsAction.dispose(); + } + }, { + label: choiceNever, + isSecondary: true, + run: () => { + importantRecommendationsIgnoreList.push(id); + this.storageService.store( + 'extensionsAssistant/importantRecommendationsIgnore', + JSON.stringify(importantRecommendationsIgnoreList), + StorageScope.GLOBAL + ); + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'neverShowAgain', extensionId: name }); + this.notificationService.prompt( + Severity.Info, + localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), + [{ + label: localize('ignoreAll', "Yes, Ignore All"), + run: () => setIgnoreRecommendationsConfig(true) + }, { + label: localize('no', "No"), + run: () => setIgnoreRecommendationsConfig(false) + }] + ); + } + }], + { + sticky: true, + onCancel: () => { + /* __GDPR__ + "extensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); + } + } + ); + }); + + const mimeTypesPromise = this.extensionService.whenInstalledExtensionsRegistered() + .then(() => { + return guessMimeTypes(uri.fsPath); + }); + + Promise.all([importantTipsPromise, mimeTypesPromise]).then(result => { + + const fileExtensionSuggestionIgnoreList = JSON.parse(this.storageService.get + ('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]')); + const mimeTypes = result[1]; + + if (fileExtension) { + fileExtension = fileExtension.substr(1); // Strip the dot + } + + if (hasSuggestion || + !fileExtension || + mimeTypes.length !== 1 || + mimeTypes[0] !== MIME_UNKNOWN || + fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1 + ) { + return; + } + + const lookup = product.extensionKeywords || {}; + const keywords = lookup[fileExtension] || []; + this._galleryService.query({ text: `tag:"__ext_${fileExtension}" ${keywords.map(tag => `tag:"${tag}"`)}` }, CancellationToken.None).then(pager => { + if (!pager || !pager.firstPage || !pager.firstPage.length) { + return; + } + this.notificationService.prompt( Severity.Info, - localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), + localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension), [{ - label: localize('ignoreAll', "Yes, Ignore All"), - run: () => setIgnoreRecommendationsConfig(true) + label: searchMarketplace, + run: () => { + /* __GDPR__ + "fileExtensionSuggestion:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension: fileExtension }); + this.viewletService.openViewlet('workbench.view.extensions', true) + .then(viewlet => viewlet as IExtensionsViewlet) + .then(viewlet => { + viewlet.search(`ext:${fileExtension}`); + viewlet.focus(); + }); + } }, { - label: localize('no', "No"), - run: () => setIgnoreRecommendationsConfig(false) - }] + label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension), + run: () => { + fileExtensionSuggestionIgnoreList.push(fileExtension); + this.storageService.store( + 'extensionsAssistant/fileExtensionsSuggestionIgnore', + JSON.stringify(fileExtensionSuggestionIgnoreList), + StorageScope.GLOBAL + ); + /* __GDPR__ + "fileExtensionSuggestion:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension }); + } + }], + { + sticky: true, + onCancel: () => { + /* __GDPR__ + "fileExtensionSuggestion:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension }); + } + } ); - } - }], - { - sticky: true, - onCancel: () => { - /* __GDPR__ - "extensionRecommendations:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('extensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); - } - } - ); - - return true; - } - - private async promptRecommendedExtensionForFileExtension(fileExtension: string, installed: ILocalExtension[]): Promise { - const fileExtensionSuggestionIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/fileExtensionsSuggestionIgnore', StorageScope.GLOBAL, '[]')); - if (fileExtensionSuggestionIgnoreList.indexOf(fileExtension) > -1) { - return; - } - - const text = `ext:${fileExtension}`; - const pager = await this.extensionWorkbenchService.queryGallery({ text, pageSize: 100 }, CancellationToken.None); - if (pager.firstPage.length === 0) { - return; - } - - const installedExtensionsIds = installed.reduce((result, i) => { result.add(i.identifier.id.toLowerCase()); return result; }, new Set()); - if (pager.firstPage.some(e => installedExtensionsIds.has(e.identifier.id.toLowerCase()))) { - return; - } - - this.notificationService.prompt( - Severity.Info, - localize('showLanguageExtensions', "The Marketplace has extensions that can help with '.{0}' files", fileExtension), - [{ - label: searchMarketplace, - run: () => { - /* __GDPR__ - "fileExtensionSuggestion:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'ok', fileExtension: fileExtension }); - this.viewletService.openViewlet('workbench.view.extensions', true) - .then(viewlet => viewlet as IExtensionsViewlet) - .then(viewlet => { - viewlet.search(`ext:${fileExtension}`); - viewlet.focus(); - }); - } - }, { - label: localize('dontShowAgainExtension', "Don't Show Again for '.{0}' files", fileExtension), - run: () => { - fileExtensionSuggestionIgnoreList.push(fileExtension); - this.storageService.store( - 'extensionsAssistant/fileExtensionsSuggestionIgnore', - JSON.stringify(fileExtensionSuggestionIgnoreList), - StorageScope.GLOBAL - ); - /* __GDPR__ - "fileExtensionSuggestion:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'neverShowAgain', fileExtension: fileExtension }); - } - }], - { - sticky: true, - onCancel: () => { - /* __GDPR__ - "fileExtensionSuggestion:popup" : { - "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "fileExtension": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('fileExtensionSuggestion:popup', { userReaction: 'cancelled', fileExtension: fileExtension }); - } - } - ); + }); + }); + }); } //#endregion @@ -1012,8 +1001,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe }), StorageScope.WORKSPACE); /* __GDPR__ "dynamicWorkspaceRecommendations" : { - "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, - "cache" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } + "count" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "cache" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } } */ this.telemetryService.publicLog('dynamicWorkspaceRecommendations', { count: this._dynamicWorkspaceRecommendations.length, cache: 0 }); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts index 6270836f0b..19b1f6890b 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensions.contribution.ts @@ -50,7 +50,6 @@ import { ExtensionsAutoProfiler } from 'vs/workbench/contrib/extensions/electron import { onUnexpectedError } from 'vs/base/common/errors'; import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/electron-browser/extensionsDependencyChecker'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ExtensionType } from 'vs/platform/extensions/common/extensions'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -422,34 +421,3 @@ CommandsRegistry.registerCommand({ } } }); - -CommandsRegistry.registerCommand({ - id: 'workbench.extensions.uninstallExtension', - description: { - description: localize('workbench.extensions.uninstallExtension.description', "Uninstall the given extension"), - args: [ - { - name: localize('workbench.extensions.uninstallExtension.arg.name', "Id of the extension to uninstall"), - schema: { - 'type': 'string' - } - } - ] - }, - handler: async (accessor, id: string) => { - if (!id) { - throw new Error(localize('id required', "Extension id required.")); - } - const extensionManagementService = accessor.get(IExtensionManagementService); - try { - const installed = await extensionManagementService.getInstalled(ExtensionType.User); - const [extensionToUninstall] = installed.filter(e => areSameExtensions(e.identifier, { id })); - if (!extensionToUninstall) { - return Promise.reject(new Error(localize('notInstalled', "Extension '{0}' is not installed. Make sure you use the full extension ID, including the publisher, e.g.: ms-vscode.csharp.", id))); - } - await extensionManagementService.uninstall(extensionToUninstall, true); - } catch (e) { - onUnexpectedError(e); - } - } -}); \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts index 0472c07b0d..3da5e438f0 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActions.ts @@ -12,7 +12,7 @@ import { Event } from 'vs/base/common/event'; import * as json from 'vs/base/common/json'; import { ActionViewItem, Separator, IActionViewItemOptions } from 'vs/base/browser/ui/actionbar/actionbar'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; -import { dispose, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; // {{SQL CARBON EDIT}} import { IExtension, ExtensionState, IExtensionsWorkbenchService, VIEWLET_ID, IExtensionsViewlet, AutoUpdateConfigurationKey, IExtensionContainer, EXTENSIONS_CONFIG, ExtensionsPolicy, ExtensionsPolicyKey } from 'vs/workbench/contrib/extensions/common/extensions'; import { ExtensionsConfigurationInitialContent } from 'vs/workbench/contrib/extensions/common/extensionsFileTemplate'; @@ -58,11 +58,10 @@ import { coalesce } from 'vs/base/common/arrays'; import { IWorkbenchThemeService, COLOR_THEME_SETTING, ICON_THEME_SETTING, IFileIconTheme, IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService'; import { ILabelService } from 'vs/platform/label/common/label'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; -import { IProductService } from 'vs/platform/product/common/product'; // {{SQL CARBON EDIT}} import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; @@ -152,6 +151,7 @@ export class InstallAction extends ExtensionAction { private static readonly Class = 'extension-action prominent install'; private static readonly InstallingClass = 'extension-action install installing'; + private disposables: IDisposable[] = []; private _manifest: IExtensionManifest | null; set manifest(manifest: IExtensionManifest) { @@ -168,12 +168,11 @@ export class InstallAction extends ExtensionAction { @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, @ILabelService private readonly labelService: ILabelService ) { super(`extensions.install`, InstallAction.INSTALL_LABEL, InstallAction.Class, false); this.update(); - this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); + this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables); } update(): void { @@ -198,7 +197,7 @@ export class InstallAction extends ExtensionAction { this.tooltip = InstallAction.INSTALLING_LABEL; } else { if (this._manifest && this.workbenchEnvironmentService.configuration.remoteAuthority) { - if (isUIExtension(this._manifest, this.productService, this.configurationService)) { + if (isUIExtension(this._manifest, this.configurationService)) { this.label = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; this.tooltip = `${InstallAction.INSTALL_LABEL} ${localize('locally', "Locally")}`; } else { @@ -282,6 +281,11 @@ export class InstallAction extends ExtensionAction { } return null; } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class RemoteInstallAction extends ExtensionAction { @@ -293,6 +297,7 @@ export class RemoteInstallAction extends ExtensionAction { private static readonly InstallingClass = 'extension-action install installing'; updateWhenCounterExtensionChanges: boolean = true; + private disposables: IDisposable[] = []; private installing: boolean = false; constructor( @@ -301,10 +306,9 @@ export class RemoteInstallAction extends ExtensionAction { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, ) { super(`extensions.remoteinstall`, RemoteInstallAction.INSTALL_LABEL, RemoteInstallAction.Class, false); - this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); + this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables); this.updateLabel(); this.update(); } @@ -337,7 +341,7 @@ export class RemoteInstallAction extends ExtensionAction { // Installed User Extension && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed // Local Workspace Extension - && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) + && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || !isUIExtension(this.extension.local.manifest, this.configurationService)) // Extension does not exist in remote && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer) && this.extensionsWorkbenchService.canInstall(this.extension) @@ -361,6 +365,11 @@ export class RemoteInstallAction extends ExtensionAction { } } } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class LocalInstallAction extends ExtensionAction { @@ -372,6 +381,7 @@ export class LocalInstallAction extends ExtensionAction { private static readonly InstallingClass = 'extension-action install installing'; updateWhenCounterExtensionChanges: boolean = true; + private disposables: IDisposable[] = []; private installing: boolean = false; constructor( @@ -380,10 +390,9 @@ export class LocalInstallAction extends ExtensionAction { @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, ) { super(`extensions.localinstall`, LocalInstallAction.INSTALL_LABEL, LocalInstallAction.Class, false); - this._register(this.labelService.onDidChangeFormatters(() => this.updateLabel(), this)); + this.labelService.onDidChangeFormatters(() => this.updateLabel(), this, this.disposables); this.updateLabel(); this.update(); } @@ -411,7 +420,7 @@ export class LocalInstallAction extends ExtensionAction { // Installed User Extension && this.extension && this.extension.local && this.extension.type === ExtensionType.User && this.extension.state === ExtensionState.Installed // Remote UI or Language pack Extension - && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) + && this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && (isLanguagePackExtension(this.extension.local.manifest) || isUIExtension(this.extension.local.manifest, this.configurationService)) // Extension does not exist in local && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.localExtensionManagementServer) && this.extensionsWorkbenchService.canInstall(this.extension) @@ -435,6 +444,11 @@ export class LocalInstallAction extends ExtensionAction { } } } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class UninstallAction extends ExtensionAction { @@ -469,7 +483,6 @@ export class UninstallAction extends ExtensionAction { this.label = UninstallAction.UninstallLabel; this.class = UninstallAction.UninstallClass; - this.tooltip = UninstallAction.UninstallLabel; if (state !== ExtensionState.Installed) { this.enabled = false; @@ -499,14 +512,16 @@ export class CombinedInstallAction extends ExtensionAction { private static readonly NoExtensionClass = 'extension-action prominent install no-extension'; private installAction: InstallAction; private uninstallAction: UninstallAction; + private disposables: IDisposable[] = []; constructor( @IInstantiationService instantiationService: IInstantiationService ) { super('extensions.combinedInstall', '', '', false); - this.installAction = this._register(instantiationService.createInstance(InstallAction)); - this.uninstallAction = this._register(instantiationService.createInstance(UninstallAction)); + this.installAction = instantiationService.createInstance(InstallAction); + this.uninstallAction = instantiationService.createInstance(UninstallAction); + this.disposables.push(this.installAction, this.uninstallAction); this.update(); } @@ -559,6 +574,11 @@ export class CombinedInstallAction extends ExtensionAction { return Promise.resolve(); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class UpdateAction extends ExtensionAction { @@ -668,6 +688,8 @@ export class ExtensionActionViewItem extends ActionViewItem { export abstract class ExtensionDropDownAction extends ExtensionAction { + protected disposables: IDisposable[] = []; + constructor( id: string, label: string, @@ -691,10 +713,17 @@ export abstract class ExtensionDropDownAction extends ExtensionAction { } return Promise.resolve(); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export class DropDownMenuActionViewItem extends ExtensionActionViewItem { + private disposables: IDisposable[] = []; + constructor(action: ExtensionDropDownAction, tabOnlyOnFocus: boolean, @IContextMenuService private readonly contextMenuService: IContextMenuService @@ -723,6 +752,11 @@ export class DropDownMenuActionViewItem extends ExtensionActionViewItem { } return actions.length ? actions.slice(0, actions.length - 1) : actions; } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class ManageExtensionAction extends ExtensionDropDownAction { @@ -1174,6 +1208,8 @@ export class UpdateAllAction extends Action { static readonly ID = 'workbench.extensions.action.updateAllExtensions'; static LABEL = localize('updateAll', "Update All Extensions"); + private disposables: IDisposable[] = []; + constructor( id = UpdateAllAction.ID, label = UpdateAllAction.LABEL, @@ -1184,7 +1220,7 @@ export class UpdateAllAction extends Action { ) { super(id, label, '', false); - this._register(this.extensionsWorkbenchService.onChange(() => this.update())); + this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); this.update(); } @@ -1207,6 +1243,11 @@ export class UpdateAllAction extends Action { return promptDownloadManually(extension.gallery, localize('failedToUpdate', "Failed to update \'{0}\'.", extension.identifier.id), err, this.instantiationService, this.notificationService, this.openerService); }); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class ReloadAction extends ExtensionAction { @@ -1215,6 +1256,7 @@ export class ReloadAction extends ExtensionAction { private static readonly DisabledClass = `${ReloadAction.EnabledClass} disabled`; updateWhenCounterExtensionChanges: boolean = true; + private disposables: IDisposable[] = []; private _runningExtensions: IExtensionDescription[] | null = null; constructor( @@ -1224,11 +1266,10 @@ export class ReloadAction extends ExtensionAction { @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super('extensions.reload', localize('reloadAction', "Reload"), ReloadAction.DisabledClass, false); - this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); + this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables); this.updateRunningExtensions(); } @@ -1309,7 +1350,7 @@ export class ReloadAction extends ExtensionAction { return; } if (this.workbenchEnvironmentService.configuration.remoteAuthority) { - const uiExtension = isUIExtension(this.extension.local.manifest, this.productService, this.configurationService); + const uiExtension = isUIExtension(this.extension.local.manifest, this.configurationService); // Local Workspace Extension if (!uiExtension && this.extension.server === this.extensionManagementServerService.localExtensionManagementServer) { const remoteExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.extensionManagementServerService.remoteExtensionManagementServer)[0]; @@ -1342,6 +1383,11 @@ export class ReloadAction extends ExtensionAction { run(): Promise { return Promise.resolve(this.windowService.reloadWindow()); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export class SetColorThemeAction extends ExtensionAction { @@ -1353,6 +1399,7 @@ export class SetColorThemeAction extends ExtensionAction { private static readonly EnabledClass = 'extension-action theme'; private static readonly DisabledClass = `${SetColorThemeAction.EnabledClass} disabled`; + private disposables: IDisposable[] = []; constructor( private readonly colorThemes: IColorTheme[], @@ -1362,7 +1409,7 @@ export class SetColorThemeAction extends ExtensionAction { @IConfigurationService private readonly configurationService: IConfigurationService ) { super(`extensions.colorTheme`, localize('color theme', "Set Color Theme"), SetColorThemeAction.DisabledClass, false); - this._register(Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this)); + Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidColorThemeChange)(() => this.update(), this, this.disposables); this.update(); } @@ -1408,6 +1455,11 @@ export class SetColorThemeAction extends ExtensionAction { const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; return this.workbenchThemeService.setColorTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target); } + + dispose() { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class SetFileIconThemeAction extends ExtensionAction { @@ -1415,6 +1467,7 @@ export class SetFileIconThemeAction extends ExtensionAction { private static readonly EnabledClass = 'extension-action theme'; private static readonly DisabledClass = `${SetFileIconThemeAction.EnabledClass} disabled`; + private disposables: IDisposable[] = []; static getFileIconThemes(fileIconThemes: IFileIconTheme[], extension: IExtension): IFileIconTheme[] { return fileIconThemes.filter(c => c.extensionData && ExtensionIdentifier.equals(c.extensionData.extensionId, extension.identifier.id)); @@ -1428,7 +1481,7 @@ export class SetFileIconThemeAction extends ExtensionAction { @IConfigurationService private readonly configurationService: IConfigurationService ) { super(`extensions.fileIconTheme`, localize('file icon theme', "Set File Icon Theme"), SetFileIconThemeAction.DisabledClass, false); - this._register(Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this)); + Event.any(extensionService.onDidChangeExtensions, workbenchThemeService.onDidFileIconThemeChange)(() => this.update(), this, this.disposables); this.update(); } @@ -1474,6 +1527,11 @@ export class SetFileIconThemeAction extends ExtensionAction { const target = typeof confValue.workspace !== 'undefined' ? ConfigurationTarget.WORKSPACE : ConfigurationTarget.USER; return this.workbenchThemeService.setFileIconTheme(pickedTheme ? pickedTheme.id : currentTheme.id, target); } + + dispose() { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class OpenExtensionsViewletAction extends ShowViewletAction { @@ -1571,6 +1629,8 @@ export class ClearExtensionsInputAction extends Action { static readonly ID = 'workbench.extensions.action.clearExtensionsInput'; static LABEL = localize('clearExtensionsInput', "Clear Extensions Input"); + private disposables: IDisposable[] = []; + constructor( id: string, label: string, @@ -1580,7 +1640,7 @@ export class ClearExtensionsInputAction extends Action { ) { super(id, label, 'clear-extensions', true); this.onSearchChange(value); - this._register(onSearchChange(this.onSearchChange, this)); + onSearchChange(this.onSearchChange, this, this.disposables); } private onSearchChange(value: string): void { @@ -1595,6 +1655,10 @@ export class ClearExtensionsInputAction extends Action { viewlet.focus(); }); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export class ShowBuiltInExtensionsAction extends Action { @@ -1708,8 +1772,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action { @IOpenerService private readonly openerService: IOpenerService, @IExtensionsWorkbenchService private readonly extensionWorkbenchService: IExtensionsWorkbenchService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @IProductService private readonly productService: IProductService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { super(id, label, 'extension-action'); this.recommendations = recommendations; @@ -1736,7 +1799,7 @@ export class InstallWorkspaceRecommendedExtensionsAction extends Action { private async installExtension(extension: IExtension): Promise { try { if (extension.local && extension.gallery) { - if (isUIExtension(extension.local.manifest, this.productService, this.configurationService)) { + if (isUIExtension(extension.local.manifest, this.configurationService)) { await this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(extension.gallery); return; } else if (this.extensionManagementServerService.remoteExtensionManagementServer) { @@ -1799,6 +1862,7 @@ export class IgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action ignore'; + private disposables: IDisposable[] = []; extension: IExtension; constructor( @@ -1815,6 +1879,11 @@ export class IgnoreExtensionRecommendationAction extends Action { this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, true); return Promise.resolve(); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class UndoIgnoreExtensionRecommendationAction extends Action { @@ -1823,6 +1892,7 @@ export class UndoIgnoreExtensionRecommendationAction extends Action { private static readonly Class = 'extension-action undo-ignore'; + private disposables: IDisposable[] = []; extension: IExtension; constructor( @@ -1839,6 +1909,11 @@ export class UndoIgnoreExtensionRecommendationAction extends Action { this.extensionsTipsService.toggleIgnoredRecommendation(this.extension.identifier.id, false); return Promise.resolve(); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } @@ -1914,6 +1989,7 @@ export class ShowAzureExtensionsAction extends Action { export class ChangeSortAction extends Action { private query: Query; + private disposables: IDisposable[] = []; constructor( id: string, @@ -1930,7 +2006,7 @@ export class ChangeSortAction extends Action { this.query = Query.parse(''); this.enabled = false; - this._register(onSearchChange(this.onSearchChange, this)); + onSearchChange(this.onSearchChange, this, this.disposables); } private onSearchChange(value: string): void { @@ -2235,6 +2311,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi static readonly ID = 'workbench.extensions.action.configureWorkspaceRecommendedExtensions'; static LABEL = localize('configureWorkspaceRecommendedExtensions', "Configure Recommended Extensions (Workspace)"); + private disposables: IDisposable[] = []; constructor( id: string, @@ -2247,7 +2324,7 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi @ITextModelService textModelResolverService: ITextModelService ) { super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService); - this._register(this.contextService.onDidChangeWorkbenchState(() => this.update(), this)); + this.contextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); this.update(); } @@ -2264,6 +2341,11 @@ export class ConfigureWorkspaceRecommendedExtensionsAction extends AbstractConfi } return Promise.resolve(); } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends AbstractConfigureRecommendedExtensionsAction { @@ -2271,6 +2353,7 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac static readonly ID = 'workbench.extensions.action.configureWorkspaceFolderRecommendedExtensions'; static LABEL = localize('configureWorkspaceFolderRecommendedExtensions', "Configure Recommended Extensions (Workspace Folder)"); + private disposables: IDisposable[] = []; constructor( id: string, @@ -2284,7 +2367,7 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac @ICommandService private readonly commandService: ICommandService ) { super(id, label, contextService, fileService, textFileService, editorService, jsonEditingService, textModelResolverService); - this._register(this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this)); + this.contextService.onDidChangeWorkspaceFolders(() => this.update(), this, this.disposables); this.update(); } @@ -2303,6 +2386,11 @@ export class ConfigureWorkspaceFolderRecommendedExtensionsAction extends Abstrac return null; }); } + + dispose(): void { + this.disposables = dispose(this.disposables); + super.dispose(); + } } export class AddToWorkspaceFolderRecommendationsAction extends AbstractConfigureRecommendedExtensionsAction { @@ -2591,6 +2679,7 @@ export class DisabledLabelAction extends ExtensionAction { private static readonly Class = 'disable-status'; updateWhenCounterExtensionChanges: boolean = true; + private disposables: IDisposable[] = []; private _runningExtensions: IExtensionDescription[] | null = null; constructor( @@ -2599,8 +2688,8 @@ export class DisabledLabelAction extends ExtensionAction { @IExtensionService private readonly extensionService: IExtensionService, ) { super('extensions.disabledLabel', warningAction.tooltip, `${DisabledLabelAction.Class} hide`, false); - this._register(warningAction.onDidChange(() => this.update(), this)); - this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); + warningAction.onDidChange(() => this.update(), this, this.disposables); + this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables); this.updateRunningExtensions(); } @@ -2633,6 +2722,11 @@ export class DisabledLabelAction extends ExtensionAction { run(): Promise { return Promise.resolve(null); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export class SystemDisabledWarningAction extends ExtensionAction { @@ -2642,20 +2736,20 @@ export class SystemDisabledWarningAction extends ExtensionAction { private static readonly INFO_CLASS = `${SystemDisabledWarningAction.CLASS} info`; updateWhenCounterExtensionChanges: boolean = true; + private disposables: IDisposable[] = []; private _runningExtensions: IExtensionDescription[] | null = null; constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, @ILabelService private readonly labelService: ILabelService, @IWorkbenchEnvironmentService private readonly workbenchEnvironmentService: IWorkbenchEnvironmentService, @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, @IExtensionService private readonly extensionService: IExtensionService, ) { super('extensions.install', '', `${SystemDisabledWarningAction.CLASS} hide`, false); - this._register(this.labelService.onDidChangeFormatters(() => this.update(), this)); - this._register(this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this)); + this.labelService.onDidChangeFormatters(() => this.update(), this, this.disposables); + this.extensionService.onDidChangeExtensions(this.updateRunningExtensions, this, this.disposables); this.updateRunningExtensions(); this.update(); } @@ -2691,7 +2785,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { const runningExtensionServer = runningExtension ? this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation) : null; const localExtension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, this.extension.identifier))[0]; const localExtensionServer = localExtension ? localExtension.server : null; - if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) { + if (this.extension.server === this.extensionManagementServerService.localExtensionManagementServer && !isUIExtension(this.extension.local.manifest, this.configurationService)) { if (runningExtensionServer === this.extensionManagementServerService.remoteExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = localize('disabled locally', "Extension is enabled on '{0}' and disabled locally.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)); @@ -2703,7 +2797,7 @@ export class SystemDisabledWarningAction extends ExtensionAction { return; } } - if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.productService, this.configurationService)) { + if (this.extension.server === this.extensionManagementServerService.remoteExtensionManagementServer && isUIExtension(this.extension.local.manifest, this.configurationService)) { if (runningExtensionServer === this.extensionManagementServerService.localExtensionManagementServer) { this.class = `${SystemDisabledWarningAction.INFO_CLASS}`; this.tooltip = localize('disabled remotely', "Extension is enabled locally and disabled on '{0}'.", this.getServerLabel(this.extensionManagementServerService.remoteExtensionManagementServer)); @@ -2726,6 +2820,11 @@ export class SystemDisabledWarningAction extends ExtensionAction { run(): Promise { return Promise.resolve(null); } + + dispose(): void { + dispose(this.disposables); + super.dispose(); + } } export class DisableAllAction extends Action { @@ -2733,6 +2832,7 @@ export class DisableAllAction extends Action { static readonly ID = 'workbench.extensions.action.disableAll'; static LABEL = localize('disableAll', "Disable All Installed Extensions"); + private disposables: IDisposable[] = []; constructor( id: string = DisableAllAction.ID, label: string = DisableAllAction.LABEL, @@ -2741,7 +2841,7 @@ export class DisableAllAction extends Action { ) { super(id, label); this.update(); - this._register(this.extensionsWorkbenchService.onChange(() => this.update())); + this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { @@ -2751,6 +2851,11 @@ export class DisableAllAction extends Action { run(): Promise { return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.Disabled); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class DisableAllWorkpsaceAction extends Action { @@ -2758,6 +2863,7 @@ export class DisableAllWorkpsaceAction extends Action { static readonly ID = 'workbench.extensions.action.disableAllWorkspace'; static LABEL = localize('disableAllWorkspace', "Disable All Installed Extensions for this Workspace"); + private disposables: IDisposable[] = []; constructor( id: string = DisableAllWorkpsaceAction.ID, label: string = DisableAllWorkpsaceAction.LABEL, @@ -2766,8 +2872,8 @@ export class DisableAllWorkpsaceAction extends Action { ) { super(id, label); this.update(); - this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this)); - this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this)); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); + this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables); } private update(): void { @@ -2777,6 +2883,11 @@ export class DisableAllWorkpsaceAction extends Action { run(): Promise { return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local.filter(e => e.type === ExtensionType.User), EnablementState.WorkspaceDisabled); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class EnableAllAction extends Action { @@ -2784,6 +2895,7 @@ export class EnableAllAction extends Action { static readonly ID = 'workbench.extensions.action.enableAll'; static LABEL = localize('enableAll', "Enable All Extensions"); + private disposables: IDisposable[] = []; constructor( id: string = EnableAllAction.ID, label: string = EnableAllAction.LABEL, @@ -2792,7 +2904,7 @@ export class EnableAllAction extends Action { ) { super(id, label); this.update(); - this._register(this.extensionsWorkbenchService.onChange(() => this.update())); + this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.update())); } private update(): void { @@ -2802,6 +2914,11 @@ export class EnableAllAction extends Action { run(): Promise { return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.Enabled); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class EnableAllWorkpsaceAction extends Action { @@ -2809,6 +2926,7 @@ export class EnableAllWorkpsaceAction extends Action { static readonly ID = 'workbench.extensions.action.enableAllWorkspace'; static LABEL = localize('enableAllWorkspace', "Enable All Extensions for this Workspace"); + private disposables: IDisposable[] = []; constructor( id: string = EnableAllWorkpsaceAction.ID, label: string = EnableAllWorkpsaceAction.LABEL, @@ -2818,8 +2936,8 @@ export class EnableAllWorkpsaceAction extends Action { ) { super(id, label); this.update(); - this._register(this.extensionsWorkbenchService.onChange(() => this.update(), this)); - this._register(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this)); + this.extensionsWorkbenchService.onChange(() => this.update(), this, this.disposables); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); } private update(): void { @@ -2829,6 +2947,11 @@ export class EnableAllWorkpsaceAction extends Action { run(): Promise { return this.extensionsWorkbenchService.setEnablement(this.extensionsWorkbenchService.local, EnablementState.WorkspaceEnabled); } + + dispose(): void { + super.dispose(); + this.disposables = dispose(this.disposables); + } } export class OpenExtensionsFolderAction extends Action { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActivationProgress.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActivationProgress.ts index 7917a1b699..d7cbb6bf44 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsActivationProgress.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsActivationProgress.ts @@ -5,7 +5,7 @@ import { IWorkbenchContribution } from 'vs/workbench/common/contributions'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; import { localize } from 'vs/nls'; import { IDisposable } from 'vs/base/common/lifecycle'; import { timeout } from 'vs/base/common/async'; @@ -17,7 +17,7 @@ export class ExtensionActivationProgress implements IWorkbenchContribution { constructor( @IExtensionService extensionService: IExtensionService, - @IProgressService progressService: IProgressService, + @IProgressService2 progressService: IProgressService2, @ILogService logService: ILogService, ) { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts index f41ad19ebb..facf24f9c7 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsList.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { append, $, addClass, removeClass, toggleClass } from 'vs/base/browser/dom'; -import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { Action } from 'vs/base/common/actions'; import { ActionBar } from 'vs/base/browser/ui/actionbar/actionbar'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -118,11 +118,11 @@ export class Renderer implements IPagedRenderer { const extensionContainers: ExtensionContainers = this.instantiationService.createInstance(ExtensionContainers, [...actions, ...widgets, disabledLabelAction]); actionbar.push(actions, actionOptions); - const disposables = combinedDisposable(...actions, ...widgets, actionbar, extensionContainers); + const disposables = [...actions, ...widgets, actionbar, extensionContainers]; return { // {{SQL CARBON EDIT}} - root, element, icon, name, /*installCount, ratings,*/ author, description, disposables: [disposables], actionbar, + root, element, icon, name, /*installCount, ratings,*/ author, description, disposables, actionbar, extensionDisposables: [], set extension(extension: IExtension) { extensionContainers.extension = extension; diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts index f559cf94c1..3eb62666d2 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViewlet.ts @@ -28,7 +28,7 @@ import { IExtensionManagementService, IExtensionManagementServerService, IExtens import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import { ExtensionsListView, EnabledExtensionsView, DisabledExtensionsView, RecommendedExtensionsView, WorkspaceRecommendedExtensionsView, BuiltInExtensionsView, BuiltInThemesExtensionsView, BuiltInBasicsExtensionsView, ServerExtensionsView, DefaultRecommendedExtensionsView } from './extensionsViews'; import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import Severity from 'vs/base/common/severity'; import { IActivityService, ProgressBadge, NumberBadge } from 'vs/workbench/services/activity/common/activity'; @@ -58,7 +58,6 @@ import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { ILabelService } from 'vs/platform/label/common/label'; -import { MementoObject } from 'vs/workbench/common/memento'; interface SearchInputEvent extends Event { target: HTMLInputElement; @@ -344,12 +343,12 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio private primaryActions: IAction[]; private secondaryActions: IAction[] | null; private disposables: IDisposable[] = []; - private readonly searchViewletState: MementoObject; + private searchViewletState: object; constructor( @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService, - @IProgressService private readonly progressService: IProgressService, + @IProgressService2 private readonly progressService: IProgressService2, @IInstantiationService instantiationService: IInstantiationService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts index 9144182701..a3b4a9113a 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionsViews.ts @@ -4,10 +4,10 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { Event, Emitter } from 'vs/base/common/event'; -import { isPromiseCanceledError, getErrorMessage } from 'vs/base/common/errors'; +import { isPromiseCanceledError } from 'vs/base/common/errors'; import { PagedModel, IPagedModel, IPager, DelayedPagedModel } from 'vs/base/common/paging'; import { SortBy, SortOrder, IQueryOptions, IExtensionTipsService, IExtensionRecommendation, IExtensionManagementServer, IExtensionManagementServerService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; @@ -24,13 +24,14 @@ import { attachBadgeStyler } from 'vs/platform/theme/common/styler'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; +import { IModeService } from 'vs/editor/common/services/modeService'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { CountBadge } from 'vs/base/browser/ui/countBadge/countBadge'; import { ActionBar, Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import { InstallWorkspaceRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction, ManageExtensionAction } from 'vs/workbench/contrib/extensions/electron-browser/extensionsActions'; import { WorkbenchPagedList } from 'vs/platform/list/browser/listService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { INotificationService } from 'vs/platform/notification/common/notification'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; import { distinct, coalesce } from 'vs/base/common/arrays'; @@ -42,10 +43,9 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { IAction } from 'vs/base/common/actions'; import { ExtensionType, ExtensionIdentifier, IExtensionDescription, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import product from 'vs/platform/product/node/product'; import { CancelablePromise, createCancelablePromise } from 'vs/base/common/async'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; -import { IProductService } from 'vs/platform/product/common/product'; -import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; +import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; class ExtensionsViewState extends Disposable implements IExtensionsViewState { @@ -68,13 +68,9 @@ export interface ExtensionsListViewOptions extends IViewletViewOptions { server?: IExtensionManagementServer; } -class ExtensionListViewWarning extends Error { } - export class ExtensionsListView extends ViewletPanel { private readonly server: IExtensionManagementServer | undefined; - private messageContainer: HTMLElement; - private messageSeverityIcon: HTMLElement; private messageBox: HTMLElement; private extensionsList: HTMLElement; private badge: CountBadge; @@ -93,13 +89,13 @@ export class ExtensionsListView extends ViewletPanel { @IExtensionsWorkbenchService protected extensionsWorkbenchService: IExtensionsWorkbenchService, @IEditorService private readonly editorService: IEditorService, @IExtensionTipsService protected tipsService: IExtensionTipsService, + @IModeService private readonly modeService: IModeService, @ITelemetryService private readonly telemetryService: ITelemetryService, @IConfigurationService configurationService: IConfigurationService, @IWorkspaceContextService protected contextService: IWorkspaceContextService, @IExperimentService private readonly experimentService: IExperimentService, @IWorkbenchThemeService private readonly workbenchThemeService: IWorkbenchThemeService, - @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService, - @IProductService protected readonly productService: IProductService, + @IExtensionManagementServerService protected readonly extensionManagementServerService: IExtensionManagementServerService ) { super({ ...(options as IViewletPanelOptions), ariaHeaderLabel: options.title }, keybindingService, contextMenuService, configurationService); this.server = options.server; @@ -114,14 +110,12 @@ export class ExtensionsListView extends ViewletPanel { this.badgeContainer = append(container, $('.count-badge-wrapper')); this.badge = new CountBadge(this.badgeContainer); - this._register(attachBadgeStyler(this.badge, this.themeService)); + this.disposables.push(attachBadgeStyler(this.badge, this.themeService)); } renderBody(container: HTMLElement): void { this.extensionsList = append(container, $('.extensions-list')); - this.messageContainer = append(container, $('.message-container')); - this.messageSeverityIcon = append(this.messageContainer, $('')); - this.messageBox = append(this.messageContainer, $('.message')); + this.messageBox = append(container, $('.message')); const delegate = new Delegate(); const extensionsViewState = new ExtensionsViewState(); const renderer = this.instantiationService.createInstance(Renderer, extensionsViewState); @@ -131,20 +125,20 @@ export class ExtensionsListView extends ViewletPanel { setRowLineHeight: false, horizontalScrolling: false }) as WorkbenchPagedList; - this._register(this.list.onContextMenu(e => this.onContextMenu(e), this)); - this._register(this.list.onFocusChange(e => extensionsViewState.onFocusChange(coalesce(e.elements)), this)); - this._register(this.list); - this._register(extensionsViewState); + this.list.onContextMenu(e => this.onContextMenu(e), this, this.disposables); + this.list.onFocusChange(e => extensionsViewState.onFocusChange(coalesce(e.elements)), this, this.disposables); + this.disposables.push(this.list); + this.disposables.push(extensionsViewState); - this._register(Event.chain(this.list.onOpen) + Event.chain(this.list.onOpen) .map(e => e.elements[0]) .filter(e => !!e) - .on(this.openExtension, this)); + .on(this.openExtension, this, this.disposables); - this._register(Event.chain(this.list.onPin) + Event.chain(this.list.onPin) .map(e => e.elements[0]) .filter(e => !!e) - .on(this.pin, this)); + .on(this.pin, this, this.disposables); } protected layoutBody(height: number, width: number): void { @@ -182,11 +176,12 @@ export class ExtensionsListView extends ViewletPanel { }; - const errorCallback = (e: any) => { + const errorCallback = (e: Error) => { const model = new PagedModel([]); if (!isPromiseCanceledError(e)) { this.queryRequest = null; - this.setModel(model, e); + console.warn('Error querying extensions gallery', e); + this.setModel(model, true); } return this.list ? this.list.model : model; }; @@ -241,11 +236,7 @@ export class ExtensionsListView extends ViewletPanel { if (ExtensionsListView.isLocalExtensionsQuery(query.value) || /@builtin/.test(query.value)) { return this.queryLocal(query, options); } - return this.queryGallery(query, options, token) - .then(null, e => { - console.warn('Error querying extensions gallery', getErrorMessage(e)); - return Promise.reject(new ExtensionListViewWarning(localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later."))); - }); + return this.queryGallery(query, options, token); } private async queryByIds(ids: string[], options: IQueryOptions, token: CancellationToken): Promise> { @@ -440,11 +431,29 @@ export class ExtensionsListView extends ViewletPanel { return this.getCuratedModel(query, options, token); } - const text = query.value; + let text = query.value; + const extensionRegex = /\bext:([^\s]+)\b/g; - if (/\bext:([^\s]+)\b/g.test(text)) { - options = assign(options, { text, source: 'file-extension-tags' }); - return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager)); + if (extensionRegex.test(query.value)) { + text = query.value.replace(extensionRegex, (m, ext) => { + + // Get curated keywords + const lookup = product.extensionKeywords || {}; + const keywords = lookup[ext] || []; + + // Get mode name + const modeId = this.modeService.getModeIdByFilepathOrFirstLine(`.${ext}`); + const languageName = modeId && this.modeService.getLanguageName(modeId); + const languageTag = languageName ? ` tag:"${languageName}"` : ''; + + // Construct a rich query + return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag} tag:"${ext}"`; + }); + + if (text !== query.value) { + options = assign(options, { text: text.substr(0, 350), source: 'file-extension-tags' }); + return this.extensionsWorkbenchService.queryGallery(options, token).then(pager => this.getPagedModel(pager)); + } } let preferredResults: string[] = []; @@ -724,36 +733,28 @@ export class ExtensionsListView extends ViewletPanel { }); } - private setModel(model: IPagedModel, error?: any) { + private setModel(model: IPagedModel, isGalleryError?: boolean) { if (this.list) { this.list.model = new DelayedPagedModel(model); this.list.scrollTop = 0; const count = this.count(); toggleClass(this.extensionsList, 'hidden', count === 0); - toggleClass(this.messageContainer, 'hidden', count > 0); + toggleClass(this.messageBox, 'hidden', count > 0); this.badge.setCount(count); if (count === 0 && this.isBodyVisible()) { - if (error) { - if (error instanceof ExtensionListViewWarning) { - this.messageSeverityIcon.className = SeverityIcon.className(Severity.Warning); - this.messageBox.textContent = getErrorMessage(error); - } else { - this.messageSeverityIcon.className = SeverityIcon.className(Severity.Error); - this.messageBox.textContent = localize('error', "Error while loading extensions. {0}", getErrorMessage(error)); - } - } else { - this.messageSeverityIcon.className = ''; - this.messageBox.textContent = localize('no extensions found', "No extensions found."); + this.messageBox.textContent = isGalleryError ? localize('galleryError', "We cannot connect to the Extensions Marketplace at this time, please try again later.") : localize('no extensions found', "No extensions found."); + if (isGalleryError) { + alert(this.messageBox.textContent); } - alert(this.messageBox.textContent); + } else { + this.messageBox.textContent = ''; } } } private openExtension(extension: IExtension): void { - extension = this.extensionsWorkbenchService.local.filter(e => areSameExtensions(e.identifier, extension.identifier))[0] || extension; this.extensionsWorkbenchService.open(extension).then(undefined, err => this.onError(err)); } @@ -805,6 +806,7 @@ export class ExtensionsListView extends ViewletPanel { this.queryRequest.request.cancel(); this.queryRequest = null; } + this.disposables = dispose(this.disposables); this.list = null; } @@ -884,18 +886,18 @@ export class ServerExtensionsView extends ExtensionsListView { @IExtensionService extensionService: IExtensionService, @IEditorService editorService: IEditorService, @IExtensionTipsService tipsService: IExtensionTipsService, + @IModeService modeService: IModeService, @ITelemetryService telemetryService: ITelemetryService, @IConfigurationService configurationService: IConfigurationService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IExperimentService experimentService: IExperimentService, @IWorkbenchThemeService workbenchThemeService: IWorkbenchThemeService, @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService, - @IProductService productService: IProductService, + @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService ) { options.server = server; - super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService, productService); - this._register(onDidChangeTitle(title => this.updateTitle(title))); + super(options, notificationService, keybindingService, contextMenuService, instantiationService, themeService, extensionService, extensionsWorkbenchService, editorService, tipsService, modeService, telemetryService, configurationService, contextService, experimentService, workbenchThemeService, extensionManagementServerService); + this.disposables.push(onDidChangeTitle(title => this.updateTitle(title))); } async show(query: string): Promise> { @@ -948,7 +950,7 @@ export class DefaultRecommendedExtensionsView extends ExtensionsListView { renderBody(container: HTMLElement): void { super.renderBody(container); - this._register(this.tipsService.onRecommendationChange(() => { + this.disposables.push(this.tipsService.onRecommendationChange(() => { this.show(''); })); } @@ -973,7 +975,7 @@ export class RecommendedExtensionsView extends ExtensionsListView { renderBody(container: HTMLElement): void { super.renderBody(container); - this._register(this.tipsService.onRecommendationChange(() => { + this.disposables.push(this.tipsService.onRecommendationChange(() => { this.show(''); })); } @@ -991,9 +993,9 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { renderBody(container: HTMLElement): void { super.renderBody(container); - this._register(this.tipsService.onRecommendationChange(() => this.update())); - this._register(this.extensionsWorkbenchService.onChange(() => this.setRecommendationsToInstall())); - this._register(this.contextService.onDidChangeWorkbenchState(() => this.update())); + this.disposables.push(this.tipsService.onRecommendationChange(() => this.update())); + this.disposables.push(this.extensionsWorkbenchService.onChange(() => this.setRecommendationsToInstall())); + this.disposables.push(this.contextService.onDidChangeWorkbenchState(() => this.update())); } renderHeader(container: HTMLElement): void { @@ -1002,19 +1004,21 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { const listActionBar = $('.list-actionbar-container'); container.insertBefore(listActionBar, this.badgeContainer); - const actionbar = this._register(new ActionBar(listActionBar, { + const actionbar = new ActionBar(listActionBar, { animated: false - })); + }); actionbar.onDidRun(({ error }) => error && this.notificationService.error(error)); - this.installAllAction = this._register(this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, [])); - const configureWorkspaceFolderAction = this._register(this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL)); + this.installAllAction = this.instantiationService.createInstance(InstallWorkspaceRecommendedExtensionsAction, InstallWorkspaceRecommendedExtensionsAction.ID, InstallWorkspaceRecommendedExtensionsAction.LABEL, []); + const configureWorkspaceFolderAction = this.instantiationService.createInstance(ConfigureWorkspaceFolderRecommendedExtensionsAction, ConfigureWorkspaceFolderRecommendedExtensionsAction.ID, ConfigureWorkspaceFolderRecommendedExtensionsAction.LABEL); this.installAllAction.class = 'octicon octicon-cloud-download'; configureWorkspaceFolderAction.class = 'octicon octicon-pencil'; actionbar.push([this.installAllAction], { icon: true, label: false }); actionbar.push([configureWorkspaceFolderAction], { icon: true, label: false }); + + this.disposables.push(...[this.installAllAction, configureWorkspaceFolderAction, actionbar]); } async show(query: string): Promise> { @@ -1041,7 +1045,7 @@ export class WorkspaceRecommendedExtensionsView extends ExtensionsListView { if (!extension || !extension.local || extension.state !== ExtensionState.Installed) { return true; } - return isUIExtension(extension.local.manifest, this.productService, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer; + return isUIExtension(extension.local.manifest, this.configurationService) ? extension.server !== this.extensionManagementServerService.localExtensionManagementServer : extension.server !== this.extensionManagementServerService.remoteExtensionManagementServer; })); } } diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css index a9bed9f79d..a6fc803419 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionActions.css @@ -81,6 +81,22 @@ width: 10px; } +.monaco-action-bar .action-item .action-label.system-disable.warning.icon { + background: url('status-warning.svg') center center no-repeat; +} + +.vs-dark .monaco-action-bar .action-item .action-label.system-disable.warning.icon { + background: url('status-warning-inverse.svg') center center no-repeat; +} + +.monaco-action-bar .action-item .action-label.system-disable.info.icon { + background: url('status-info.svg') center center no-repeat; +} + +.vs-dark .monaco-action-bar .action-item .action-label.system-disable.info.icon { + background: url('status-info-inverse.svg') center center no-repeat; +} + .extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.extension-status-label, .extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.disable-status, .extension-editor>.header>.details>.actions>.monaco-action-bar .action-item .action-label.malicious-status { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css index 31ef0ba3e0..38d72359d3 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/extensionsViewlet.css @@ -38,7 +38,7 @@ } .extensions-viewlet > .extensions .extensions-list.hidden, -.extensions-viewlet > .extensions .message-container.hidden { +.extensions-viewlet > .extensions .message.hidden { display: none; visibility: hidden; } @@ -51,14 +51,9 @@ flex: 1; } -.extensions-viewlet > .extensions .message-container { +.extensions-viewlet > .extensions .message { padding: 5px 9px 5px 16px; cursor: default; - display: flex; -} - -.extensions-viewlet > .extensions .message-container .message { - padding-left: 5px; } .extensions-viewlet > .extensions .monaco-list-row > .bookmark { diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/runtimeExtensionsEditor.css b/src/vs/workbench/contrib/extensions/electron-browser/media/runtimeExtensionsEditor.css index 18a6e43b20..84a2d36bc1 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/media/runtimeExtensionsEditor.css +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/runtimeExtensionsEditor.css @@ -36,3 +36,20 @@ .runtime-extensions-editor .monaco-action-bar .actions-container { justify-content: left; } + +.monaco-workbench .part.statusbar .profileExtHost-statusbar-item .icon { + background: url('profile-stop.svg') no-repeat; + display: inline-block; + padding-right: 2px; + padding-bottom: 2px; + width: 16px; + height: 16px; + vertical-align: middle; + animation:fade 1000ms infinite; +} + +@keyframes fade { + from { opacity: 1.0; } + 50% { opacity: 0.5; } + to { opacity: 1.0; } +} diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/status-info-inverse.svg b/src/vs/workbench/contrib/extensions/electron-browser/media/status-info-inverse.svg new file mode 100644 index 0000000000..d38c363e0e --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/status-info-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/status-info.svg b/src/vs/workbench/contrib/extensions/electron-browser/media/status-info.svg new file mode 100644 index 0000000000..6e2e22f67b --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/status-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning-inverse.svg b/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning-inverse.svg new file mode 100644 index 0000000000..df44e61b32 --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning.svg b/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning.svg new file mode 100644 index 0000000000..f4e2a84b0a --- /dev/null +++ b/src/vs/workbench/contrib/extensions/electron-browser/media/status-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts index e9651cdc65..071714d31f 100644 --- a/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/node/extensionsWorkbenchService.ts @@ -9,7 +9,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { index, distinct } from 'vs/base/common/arrays'; import { ThrottledDelayer } from 'vs/base/common/async'; import { isPromiseCanceledError } from 'vs/base/common/errors'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IPager, mapPager, singlePagePager } from 'vs/base/common/paging'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; // {{SQL CARBON EDIT}} @@ -17,7 +17,7 @@ import { IExtensionManagementService, IExtensionGalleryService, ILocalExtension, IGalleryExtension, IQueryOptions, InstallExtensionEvent, DidInstallExtensionEvent, DidUninstallExtensionEvent, IExtensionEnablementService, IExtensionIdentifier, EnablementState, IExtensionManagementServerService, IExtensionManagementServer, INSTALL_ERROR_INCOMPATIBLE } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionTelemetryData, getLocalExtensionTelemetryData, areSameExtensions, getMaliciousExtensionsSet, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -29,14 +29,13 @@ import { IURLService, IURLHandler } from 'vs/platform/url/common/url'; import { ExtensionsInput } from 'vs/workbench/contrib/extensions/common/extensionsInput'; import product from 'vs/platform/product/node/product'; import { ILogService } from 'vs/platform/log/common/log'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; import { INotificationService } from 'vs/platform/notification/common/notification'; import * as resources from 'vs/base/common/resources'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { IFileService } from 'vs/platform/files/common/files'; -import { IExtensionManifest, ExtensionType, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; -import { IModeService } from 'vs/editor/common/services/modeService'; +import { IExtensionManifest, ExtensionType, ExtensionIdentifierWithVersion, IExtension as IPlatformExtension, isLanguagePackExtension } from 'vs/platform/extensions/common/extensions'; // {{SQL CARBON EDIT}} import { isEngineValid } from 'vs/platform/extensions/node/extensionValidator'; @@ -498,6 +497,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension private readonly remoteExtensions: Extensions | null; private syncDelayer: ThrottledDelayer; private autoUpdateDelayer: ThrottledDelayer; + private disposables: IDisposable[] = []; private readonly _onChange: Emitter = new Emitter(); get onChange(): Event { return this._onChange.event; } @@ -516,11 +516,10 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, @ILogService private readonly logService: ILogService, - @IProgressService private readonly progressService: IProgressService, + @IProgressService2 private readonly progressService: IProgressService2, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IStorageService private readonly storageService: IStorageService, - @IFileService private readonly fileService: IFileService, - @IModeService private readonly modeService: IModeService + @IFileService private readonly fileService: IFileService ) { super(); this.localExtensions = this._register(instantiationService.createInstance(Extensions, extensionManagementServerService.localExtensionManagementServer)); @@ -537,7 +536,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension urlService.registerHandler(this); - this._register(this.configurationService.onDidChangeConfiguration(e => { + this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(AutoUpdateConfigurationKey)) { // {{SQL CARBON EDIT}} // if (this.isAutoUpdateEnabled()) { @@ -549,7 +548,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.checkForUpdates(); } } - }, this)); + }, this, this.disposables); this.queryLocal().then(() => { this.resetIgnoreAutoUpdateExtensions(); @@ -603,7 +602,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension queryGallery(arg1: any, arg2?: any): Promise> { const options: IQueryOptions = CancellationToken.isCancellationToken(arg1) ? {} : arg1; const token: CancellationToken = CancellationToken.isCancellationToken(arg1) ? arg1 : arg2; - options.text = options.text ? this.resolveQueryText(options.text) : options.text; return this.extensionService.getExtensionsReport() .then(report => { const maliciousSet = getMaliciousExtensionsSet(report); @@ -620,27 +618,6 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension }); } - private resolveQueryText(text: string): string { - const extensionRegex = /\bext:([^\s]+)\b/g; - if (extensionRegex.test(text)) { - text = text.replace(extensionRegex, (m, ext) => { - - // Get curated keywords - const lookup = product.extensionKeywords || {}; - const keywords = lookup[ext] || []; - - // Get mode name - const modeId = this.modeService.getModeIdByFilepathOrFirstLine(`.${ext}`); - const languageName = modeId && this.modeService.getLanguageName(modeId); - const languageTag = languageName ? ` tag:"${languageName}"` : ''; - - // Construct a rich query - return `tag:"__ext_${ext}" tag:"__ext_.${ext}" ${keywords.map(tag => `tag:"${tag}"`).join(' ')}${languageTag} tag:"${ext}"`; - }); - } - return text.substr(0, 350); - } - open(extension: IExtension, sideByside: boolean = false): Promise { return Promise.resolve(this.editorService.openEditor(this.instantiationService.createInstance(ExtensionsInput, extension), undefined, sideByside ? SIDE_GROUP : ACTIVE_GROUP)); } @@ -1139,7 +1116,7 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension } dispose(): void { - super.dispose(); this.syncDelayer.cancel(); + this.disposables = dispose(this.disposables); } } diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts index 8a39d844bf..5bf3b9489b 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsViews.test.ts @@ -113,7 +113,7 @@ suite('ExtensionsListView Tests', () => { instantiationService.stubPromise(IExtensionTipsService, 'getOtherRecommendations', [ { extensionId: otherRecommendationA.identifier.id } ]); - const reasons: { [key: string]: any } = {}; + const reasons = {}; reasons[workspaceRecommendationA.identifier.id] = { reasonId: ExtensionRecommendationReason.Workspace }; reasons[workspaceRecommendationB.identifier.id] = { reasonId: ExtensionRecommendationReason.Workspace }; reasons[fileBasedRecommendationA.identifier.id] = { reasonId: ExtensionRecommendationReason.File }; diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts index 2119a8da91..bae14fc8d2 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsWorkbenchService.test.ts @@ -30,8 +30,8 @@ import { TestContextService, TestWindowService, TestSharedProcessService } from import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { ILogService, NullLogService } from 'vs/platform/log/common/log'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { IProgressService } from 'vs/platform/progress/common/progress'; -import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; +import { IProgressService2 } from 'vs/platform/progress/common/progress'; +import { ProgressService2 } from 'vs/workbench/services/progress/browser/progressService2'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { URLService } from 'vs/platform/url/common/urlService'; import { URI } from 'vs/base/common/uri'; @@ -61,7 +61,7 @@ suite('ExtensionsWorkbenchServiceTest', () => { instantiationService.stub(ITelemetryService, NullTelemetryService); instantiationService.stub(ILogService, NullLogService); instantiationService.stub(IWindowService, TestWindowService); - instantiationService.stub(IProgressService, ProgressService); + instantiationService.stub(IProgressService2, ProgressService2); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); instantiationService.stub(IURLService, URLService); diff --git a/src/vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts b/src/vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts index fb3b9a36d5..a3248ca69b 100644 --- a/src/vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts +++ b/src/vs/workbench/contrib/feedback/electron-browser/feedback.contribution.ts @@ -8,12 +8,28 @@ import { IStatusbarRegistry, Extensions, StatusbarItemDescriptor } from 'vs/work import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { FeedbackStatusbarItem } from 'vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem'; import { localize } from 'vs/nls'; +import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; // Register Statusbar item Registry.as(Extensions.Statusbar).registerStatusbarItem(new StatusbarItemDescriptor( FeedbackStatusbarItem, - 'status.feedback', - localize('status.feedback', "Tweet Feedback"), StatusbarAlignment.RIGHT, -100 /* towards the end of the right hand side */ )); + +// Configuration: Workbench +const configurationRegistry = Registry.as(ConfigurationExtensions.Configuration); + +configurationRegistry.registerConfiguration({ + 'id': 'workbench', + 'order': 7, + 'title': localize('workbenchConfigurationTitle', "Workbench"), + 'type': 'object', + 'properties': { + 'workbench.statusBar.feedback.visible': { + 'type': 'boolean', + 'default': true, + 'description': localize('feedbackVisibility', "Controls the visibility of the Twitter feedback (smiley) in the status bar at the bottom of the workbench.") + } + } +}); \ No newline at end of file diff --git a/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts b/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts index 5f157f6837..e17d5c32e1 100644 --- a/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts +++ b/src/vs/workbench/contrib/feedback/electron-browser/feedback.ts @@ -18,8 +18,9 @@ import { editorWidgetBackground, widgetShadow, inputBorder, inputForeground, inp import { IAnchor } from 'vs/base/browser/ui/contextview/contextview'; import { Button } from 'vs/base/browser/ui/button/button'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; -import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export const FEEDBACK_VISIBLE_CONFIG = 'workbench.statusBar.feedback.visible'; export interface IFeedback { feedback: string; @@ -65,13 +66,12 @@ export class FeedbackDropdown extends Dropdown { @ITelemetryService private readonly telemetryService: ITelemetryService, @IIntegrityService private readonly integrityService: IIntegrityService, @IThemeService private readonly themeService: IThemeService, - @IStatusbarService private readonly statusbarService: IStatusbarService + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(container, { contextViewProvider: options.contextViewProvider, labelRenderer: (container: HTMLElement): IDisposable => { - const label = new OcticonLabel(container); - label.text = '$(smiley)'; + dom.addClasses(container, 'send-feedback', 'mask-icon'); return Disposable.None; } @@ -402,7 +402,7 @@ export class FeedbackDropdown extends Dropdown { } if (this.hideButton && !this.hideButton.checked) { - this.statusbarService.updateEntryVisibility('status.feedback', false); + this.configurationService.updateValue(FEEDBACK_VISIBLE_CONFIG, false); } super.hide(); diff --git a/src/vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts b/src/vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts index 6868307d81..5d1b9da8e9 100644 --- a/src/vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts +++ b/src/vs/workbench/contrib/feedback/electron-browser/feedbackStatusbarItem.ts @@ -5,14 +5,17 @@ import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { IStatusbarItem } from 'vs/workbench/browser/parts/statusbar/statusbar'; -import { FeedbackDropdown, IFeedback, IFeedbackDelegate } from 'vs/workbench/contrib/feedback/electron-browser/feedback'; -import { IContextViewService } from 'vs/platform/contextview/browser/contextView'; +import { FeedbackDropdown, IFeedback, IFeedbackDelegate, FEEDBACK_VISIBLE_CONFIG } from 'vs/workbench/contrib/feedback/electron-browser/feedback'; +import { IContextViewService, IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import product from 'vs/platform/product/node/product'; -import { Themable, STATUS_BAR_ITEM_HOVER_BACKGROUND } from 'vs/workbench/common/theme'; +import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND } from 'vs/workbench/common/theme'; import { IThemeService, registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService'; -import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; +import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; +import { IConfigurationChangeEvent, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { clearNode, EventHelper, addClass, removeClass, addDisposableListener } from 'vs/base/browser/dom'; +import { localize } from 'vs/nls'; +import { Action } from 'vs/base/common/actions'; class TwitterFeedbackService implements IFeedbackDelegate { @@ -49,40 +52,75 @@ class TwitterFeedbackService implements IFeedbackDelegate { export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { private dropdown: FeedbackDropdown | undefined; + private enabled: boolean; private container: HTMLElement; + private hideAction: HideAction; constructor( @IInstantiationService private readonly instantiationService: IInstantiationService, @IContextViewService private readonly contextViewService: IContextViewService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, + @IContextMenuService private readonly contextMenuService: IContextMenuService, + @IConfigurationService private readonly configurationService: IConfigurationService, @IThemeService themeService: IThemeService ) { super(themeService); + this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG); + + this.hideAction = this._register(this.instantiationService.createInstance(HideAction)); + this.registerListeners(); } private registerListeners(): void { this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); + this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(e))); + } + + private onConfigurationUpdated(event: IConfigurationChangeEvent): void { + if (event.affectsConfiguration(FEEDBACK_VISIBLE_CONFIG)) { + this.enabled = this.configurationService.getValue(FEEDBACK_VISIBLE_CONFIG); + this.update(); + } + } + + protected updateStyles(): void { + super.updateStyles(); + + if (this.dropdown && this.dropdown.label) { + this.dropdown.label.style.backgroundColor = (this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND)); + } } render(element: HTMLElement): IDisposable { this.container = element; // Prevent showing dropdown on anything but left click - this._register(addDisposableListener(this.container, 'mousedown', (e: MouseEvent) => { + this.toDispose.push(addDisposableListener(this.container, 'mousedown', (e: MouseEvent) => { if (e.button !== 0) { EventHelper.stop(e, true); } }, true)); + // Offer context menu to hide status bar entry + this.toDispose.push(addDisposableListener(this.container, 'contextmenu', e => { + EventHelper.stop(e, true); + + this.contextMenuService.showContextMenu({ + getAnchor: () => this.container, + getActions: () => [this.hideAction] + }); + })); + return this.update(); } private update(): IDisposable { + const enabled = product.sendASmile && this.enabled; // Create - if (product.sendASmile) { + if (enabled) { if (!this.dropdown) { this.dropdown = this._register(this.instantiationService.createInstance(FeedbackDropdown, this.container, { contextViewProvider: this.contextViewService, @@ -113,9 +151,22 @@ export class FeedbackStatusbarItem extends Themable implements IStatusbarItem { } } +class HideAction extends Action { + + constructor( + @IConfigurationService private readonly configurationService: IConfigurationService + ) { + super('feedback.hide', localize('hide', "Hide")); + } + + run(extensionId: string): Promise { + return this.configurationService.updateValue(FEEDBACK_VISIBLE_CONFIG, false); + } +} + registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { const statusBarItemHoverBackground = theme.getColor(STATUS_BAR_ITEM_HOVER_BACKGROUND); if (statusBarItemHoverBackground) { - collector.addRule(`.monaco-workbench .part.statusbar > .items-container > .statusbar-item .monaco-dropdown.send-feedback:hover { background-color: ${statusBarItemHoverBackground}; }`); + collector.addRule(`.monaco-workbench .part.statusbar > .statusbar-item .monaco-dropdown.send-feedback:hover { background-color: ${statusBarItemHoverBackground}; }`); } }); diff --git a/src/vs/workbench/contrib/feedback/electron-browser/media/feedback.css b/src/vs/workbench/contrib/feedback/electron-browser/media/feedback.css index 5163f47b40..c9af14d735 100644 --- a/src/vs/workbench/contrib/feedback/electron-browser/media/feedback.css +++ b/src/vs/workbench/contrib/feedback/electron-browser/media/feedback.css @@ -114,14 +114,13 @@ } /* Statusbar */ -.monaco-workbench .statusbar > .items-container > .statusbar-item > .monaco-dropdown.send-feedback { +.monaco-workbench .statusbar-item > .monaco-dropdown.send-feedback { display: inline-block; - padding: 0 5px 0 5px; } -.monaco-workbench .statusbar > .items-container > .statusbar-item > .monaco-dropdown.send-feedback span.octicon { - text-align: center; - font-size: 14px; +.monaco-workbench .statusbar-item > .monaco-dropdown.send-feedback > .dropdown-label.send-feedback { + -webkit-mask: url('smiley.svg') no-repeat 50% 50%; /* use mask to be able to change color dynamically */ + width: 26px; } /* Theming */ @@ -129,7 +128,7 @@ font-family: inherit; border: 1px solid transparent; } - + .vs .monaco-workbench .feedback-form .cancel { background: url('close.svg') center center no-repeat; } diff --git a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts index fa65027d65..230fbed257 100644 --- a/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts +++ b/src/vs/workbench/contrib/files/browser/editors/binaryFileEditor.ts @@ -14,8 +14,8 @@ import { URI } from 'vs/base/common/uri'; import { BINARY_FILE_EDITOR_ID } from 'vs/workbench/contrib/files/common/files'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IStorageService } from 'vs/platform/storage/common/storage'; +import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IFileService } from 'vs/platform/files/common/files'; /** * An implementation of editor for binary files like images. @@ -30,7 +30,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { @IWindowsService private readonly windowsService: IWindowsService, @IEditorService private readonly editorService: IEditorService, @IStorageService storageService: IStorageService, - @IFileService fileService: IFileService, + @ITextFileService textFileService: ITextFileService, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, ) { super( @@ -41,7 +41,7 @@ export class BinaryFileEditor extends BaseBinaryResourceEditor { }, telemetryService, themeService, - fileService, + textFileService, environmentService, storageService, ); diff --git a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts index e6db85cf5c..4aadc5bd6f 100644 --- a/src/vs/workbench/contrib/files/browser/explorerViewlet.ts +++ b/src/vs/workbench/contrib/files/browser/explorerViewlet.ts @@ -18,6 +18,7 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; +import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IViewsRegistry, IViewDescriptor, Extensions } from 'vs/workbench/common/views'; @@ -33,7 +34,7 @@ import { IEditorInput, IEditor } from 'vs/workbench/common/editor'; import { ViewletPanel } from 'vs/workbench/browser/parts/views/panelViewlet'; import { KeyChord, KeyMod, KeyCode } from 'vs/base/common/keyCodes'; import { Registry } from 'vs/platform/registry/common/platform'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, ProgressLocation } from 'vs/platform/progress/common/progress'; export class ExplorerViewletViewsContribution extends Disposable implements IWorkbenchContribution { @@ -43,7 +44,7 @@ export class ExplorerViewletViewsContribution extends Disposable implements IWor @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @IConfigurationService private readonly configurationService: IConfigurationService, @IContextKeyService contextKeyService: IContextKeyService, - @IProgressService progressService: IProgressService + @IProgressService2 progressService: IProgressService2 ) { super(); @@ -186,7 +187,7 @@ export class ExplorerViewlet extends ViewContainerViewlet { // We try to be smart and only use the delay if we recognize that the user action is likely to cause // a new entry in the opened editors view. const delegatingEditorService = this.instantiationService.createInstance(DelegatingEditorService); - delegatingEditorService.setEditorOpenHandler(async (group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise => { + delegatingEditorService.setEditorOpenHandler((group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise => { let openEditorsView = this.getOpenEditorsView(); if (openEditorsView) { let delay = 0; @@ -202,19 +203,16 @@ export class ExplorerViewlet extends ViewContainerViewlet { openEditorsView.setStructuralRefreshDelay(delay); } - let openedEditor: IEditor | null = null; - try { - openedEditor = await this.editorService.openEditor(editor, options, group); - } catch (error) { - // ignore - } finally { + const onSuccessOrError = (editor: BaseEditor | null) => { const openEditorsView = this.getOpenEditorsView(); if (openEditorsView) { openEditorsView.setStructuralRefreshDelay(0); } - } - return openedEditor; + return editor; + }; + + return this.editorService.openEditor(editor, options, group).then(onSuccessOrError, onSuccessOrError); }); const explorerInstantiator = this.instantiationService.createChild(new ServiceCollection([IEditorService, delegatingEditorService])); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.ts b/src/vs/workbench/contrib/files/browser/fileActions.ts index ebadf65cd1..34b7c1c196 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.ts @@ -44,6 +44,7 @@ import { coalesce } from 'vs/base/common/arrays'; import { AsyncDataTree } from 'vs/base/browser/ui/tree/asyncDataTree'; import { ExplorerItem, NewExplorerItem } from 'vs/workbench/contrib/files/common/explorerModel'; import { onUnexpectedError } from 'vs/base/common/errors'; +import { sequence } from 'vs/base/common/async'; // {{SQL CARBON EDIT}} import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement'; @@ -89,13 +90,15 @@ export class NewFileAction extends Action { static readonly ID = 'workbench.files.action.createFileFromExplorer'; static readonly LABEL = nls.localize('createNewFile', "New File"); + private toDispose: IDisposable[] = []; + constructor( @IExplorerService explorerService: IExplorerService, @ICommandService private commandService: ICommandService ) { super('explorer.newFile', NEW_FILE_LABEL); this.class = 'explorer-action new-file'; - this._register(explorerService.onDidChangeEditable(e => { + this.toDispose.push(explorerService.onDidChangeEditable(e => { const elementIsBeingEdited = explorerService.isEditable(e); this.enabled = !elementIsBeingEdited; })); @@ -104,6 +107,11 @@ export class NewFileAction extends Action { run(): Promise { return this.commandService.executeCommand(NEW_FILE_COMMAND_ID); } + + dispose(): void { + super.dispose(); + dispose(this.toDispose); + } } /* New Folder */ @@ -111,13 +119,15 @@ export class NewFolderAction extends Action { static readonly ID = 'workbench.files.action.createFolderFromExplorer'; static readonly LABEL = nls.localize('createNewFolder', "New Folder"); + private toDispose: IDisposable[] = []; + constructor( @IExplorerService explorerService: IExplorerService, @ICommandService private commandService: ICommandService ) { super('explorer.newFolder', NEW_FOLDER_LABEL); this.class = 'explorer-action new-folder'; - this._register(explorerService.onDidChangeEditable(e => { + this.toDispose.push(explorerService.onDidChangeEditable(e => { const elementIsBeingEdited = explorerService.isEditable(e); this.enabled = !elementIsBeingEdited; })); @@ -126,6 +136,11 @@ export class NewFolderAction extends Action { run(): Promise { return this.commandService.executeCommand(NEW_FOLDER_COMMAND_ID); } + + dispose(): void { + super.dispose(); + dispose(this.toDispose); + } } /* Create new file from anywhere: Open untitled */ @@ -505,6 +520,7 @@ export class ToggleAutoSaveAction extends Action { } export abstract class BaseSaveAllAction extends Action { + private toDispose: IDisposable[]; private lastIsDirty: boolean; constructor( @@ -517,6 +533,7 @@ export abstract class BaseSaveAllAction extends Action { ) { super(id, label); + this.toDispose = []; this.lastIsDirty = this.textFileService.isDirty(); this.enabled = this.lastIsDirty; @@ -529,13 +546,13 @@ export abstract class BaseSaveAllAction extends Action { private registerListeners(): void { // listen to files being changed locally - this._register(this.textFileService.models.onModelsDirty(e => this.updateEnablement(true))); - this._register(this.textFileService.models.onModelsSaved(e => this.updateEnablement(false))); - this._register(this.textFileService.models.onModelsReverted(e => this.updateEnablement(false))); - this._register(this.textFileService.models.onModelsSaveError(e => this.updateEnablement(true))); + this.toDispose.push(this.textFileService.models.onModelsDirty(e => this.updateEnablement(true))); + this.toDispose.push(this.textFileService.models.onModelsSaved(e => this.updateEnablement(false))); + this.toDispose.push(this.textFileService.models.onModelsReverted(e => this.updateEnablement(false))); + this.toDispose.push(this.textFileService.models.onModelsSaveError(e => this.updateEnablement(true))); if (this.includeUntitled()) { - this._register(this.untitledEditorService.onDidChangeDirty(resource => this.updateEnablement(this.untitledEditorService.isDirty(resource)))); + this.toDispose.push(this.untitledEditorService.onDidChangeDirty(resource => this.updateEnablement(this.untitledEditorService.isDirty(resource)))); } } @@ -552,6 +569,12 @@ export abstract class BaseSaveAllAction extends Action { return false; }); } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + + super.dispose(); + } } export class SaveAllAction extends BaseSaveAllAction { @@ -654,19 +677,15 @@ export class CollapseExplorerView extends Action { public static readonly ID = 'workbench.files.action.collapseExplorerFolders'; public static readonly LABEL = nls.localize('collapseExplorerFolders', "Collapse Folders in Explorer"); - constructor(id: string, + constructor( + id: string, label: string, - @IViewletService private readonly viewletService: IViewletService, - @IExplorerService readonly explorerService: IExplorerService + @IViewletService private readonly viewletService: IViewletService ) { - super(id, label, 'explorer-action collapse-explorer'); - this._register(explorerService.onDidChangeEditable(e => { - const elementIsBeingEdited = explorerService.isEditable(e); - this.enabled = !elementIsBeingEdited; - })); + super(id, label); } - run(): Promise { + public run(): Promise { return this.viewletService.openViewlet(VIEWLET_ID).then((viewlet: ExplorerViewlet) => { const explorerView = viewlet.getExplorerView(); if (explorerView) { @@ -681,17 +700,13 @@ export class RefreshExplorerView extends Action { public static readonly ID = 'workbench.files.action.refreshFilesExplorer'; public static readonly LABEL = nls.localize('refreshExplorer', "Refresh Explorer"); - constructor( - id: string, label: string, + id: string, + label: string, @IViewletService private readonly viewletService: IViewletService, @IExplorerService private readonly explorerService: IExplorerService ) { super(id, label, 'explorer-action refresh-explorer'); - this._register(explorerService.onDidChangeEditable(e => { - const elementIsBeingEdited = explorerService.isEditable(e); - this.enabled = !elementIsBeingEdited; - })); } public run(): Promise { @@ -763,6 +778,14 @@ export function validateFileName(item: ExplorerItem, name: string): string | nul return nls.localize('invalidFileNameError', "The name **{0}** is not valid as a file or folder name. Please choose a different name.", trimLongName(name)); } + // Max length restriction (on Windows) + if (isWindows) { + const fullPathLength = item.resource.fsPath.length + 1 /* path segment */; + if (fullPathLength > 255) { + return nls.localize('filePathTooLongError', "The name **{0}** results in a path that is too long. Please choose a shorter name.", trimLongName(name)); + } + } + return null; } @@ -886,8 +909,10 @@ async function openExplorerAndCreate(accessor: ServicesAccessor, isFolder: boole const textFileService = accessor.get(ITextFileService); const editorService = accessor.get(IEditorService); const viewletService = accessor.get(IViewletService); - - await viewletService.openViewlet(VIEWLET_ID, true); + const activeViewlet = viewletService.getActiveViewlet(); + if (!activeViewlet || activeViewlet.getId() !== VIEWLET_ID || !listService.lastFocusedList) { + await viewletService.openViewlet(VIEWLET_ID, true); + } const list = listService.lastFocusedList; if (list) { @@ -1030,7 +1055,6 @@ export const pasteFileHandler = (accessor: ServicesAccessor) => { const clipboardService = accessor.get(IClipboardService); const explorerService = accessor.get(IExplorerService); const fileService = accessor.get(IFileService); - const textFileService = accessor.get(ITextFileService); const notificationService = accessor.get(INotificationService); const editorService = accessor.get(IEditorService); @@ -1040,7 +1064,7 @@ export const pasteFileHandler = (accessor: ServicesAccessor) => { const element = explorerContext.stat || explorerService.roots[0]; // Check if target is ancestor of pasted folder - Promise.all(toPaste.map(fileToPaste => { + sequence(toPaste.map(fileToPaste => () => { if (element.resource.toString() !== fileToPaste.toString() && resources.isEqualOrParent(element.resource, fileToPaste, !isLinux /* ignorecase */)) { throw new Error(nls.localize('fileIsAncestor', "File to paste is an ancestor of the destination folder")); @@ -1058,8 +1082,8 @@ export const pasteFileHandler = (accessor: ServicesAccessor) => { const targetFile = findValidPasteFileTarget(target, { resource: fileToPaste, isDirectory: fileToPasteStat.isDirectory, allowOverwirte: pasteShouldMove }); - // Move/Copy File - return pasteShouldMove ? textFileService.move(fileToPaste, targetFile) : fileService.copy(fileToPaste, targetFile); + // Copy File + return pasteShouldMove ? fileService.move(fileToPaste, targetFile) : fileService.copy(fileToPaste, targetFile); }, error => { onError(notificationService, new Error(nls.localize('fileDeleted', "File to paste was deleted or moved meanwhile"))); }); diff --git a/src/vs/workbench/contrib/files/browser/files.contribution.ts b/src/vs/workbench/contrib/files/browser/files.contribution.ts index 1410c44463..e0f2276691 100644 --- a/src/vs/workbench/contrib/files/browser/files.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/files.contribution.ts @@ -295,7 +295,7 @@ configurationRegistry.registerConfiguration({ nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onFocusChange' }, "A dirty file is automatically saved when the editor loses focus."), nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'files.autoSave.onWindowChange' }, "A dirty file is automatically saved when the window loses focus.") ], - 'default': platform.isWeb ? AutoSaveConfiguration.AFTER_DELAY : AutoSaveConfiguration.OFF, + 'default': AutoSaveConfiguration.OFF, 'markdownDescription': nls.localize({ comment: ['This is the description for a setting. Values surrounded by single quotes are not to be translated.'], key: 'autoSave' }, "Controls auto save of dirty files. Read more about autosave [here](https://code.visualstudio.com/docs/editor/codebasics#_save-auto-save).", AutoSaveConfiguration.OFF, AutoSaveConfiguration.AFTER_DELAY, AutoSaveConfiguration.ON_FOCUS_CHANGE, AutoSaveConfiguration.ON_WINDOW_CHANGE, AutoSaveConfiguration.AFTER_DELAY) }, 'files.autoSaveDelay': { diff --git a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts index af19d0a492..f351dc5726 100644 --- a/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts +++ b/src/vs/workbench/contrib/files/browser/saveErrorHandler.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { basename } from 'vs/base/common/resources'; -import { Action, IAction } from 'vs/base/common/actions'; +import { Action } from 'vs/base/common/actions'; import { URI } from 'vs/base/common/uri'; import { FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { ITextFileService, ISaveErrorHandler, ITextFileEditorModel, IResolvedTextFileEditorModel, IWriteTextFileOptions } from 'vs/workbench/services/textfile/common/textfiles'; @@ -106,8 +106,7 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I const resource = model.getResource(); let message: string; - const primaryActions: IAction[] = []; - const secondaryActions: IAction[] = []; + const actions: INotificationActions = { primary: [], secondary: [] }; // Dirty write prevention if (fileOperationError.fileOperationResult === FileOperationResult.FILE_MODIFIED_SINCE) { @@ -120,15 +119,15 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I message = conflictEditorHelp; - primaryActions.push(this.instantiationService.createInstance(ResolveConflictLearnMoreAction)); - secondaryActions.push(this.instantiationService.createInstance(DoNotShowResolveConflictLearnMoreAction)); + actions.primary!.push(this.instantiationService.createInstance(ResolveConflictLearnMoreAction)); + actions.secondary!.push(this.instantiationService.createInstance(DoNotShowResolveConflictLearnMoreAction)); } // Otherwise show the message that will lead the user into the save conflict editor. else { message = nls.localize('staleSaveError', "Failed to save '{0}': The content of the file is newer. Please compare your version with the file contents.", basename(resource)); - primaryActions.push(this.instantiationService.createInstance(ResolveSaveConflictAction, model)); + actions.primary!.push(this.instantiationService.createInstance(ResolveSaveConflictAction, model)); } } @@ -141,24 +140,24 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I // Save Elevated if (canHandlePermissionOrReadonlyErrors && (isPermissionDenied || triedToMakeWriteable)) { - primaryActions.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable)); + actions.primary!.push(this.instantiationService.createInstance(SaveElevatedAction, model, triedToMakeWriteable)); } // Overwrite else if (canHandlePermissionOrReadonlyErrors && isReadonly) { - primaryActions.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model)); + actions.primary!.push(this.instantiationService.createInstance(OverwriteReadonlyAction, model)); } // Retry else { - primaryActions.push(this.instantiationService.createInstance(ExecuteCommandAction, SAVE_FILE_COMMAND_ID, nls.localize('retry', "Retry"))); + actions.primary!.push(this.instantiationService.createInstance(ExecuteCommandAction, SAVE_FILE_COMMAND_ID, nls.localize('retry', "Retry"))); } // Save As - primaryActions.push(this.instantiationService.createInstance(ExecuteCommandAction, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL)); + actions.primary!.push(this.instantiationService.createInstance(ExecuteCommandAction, SAVE_FILE_AS_COMMAND_ID, SAVE_FILE_AS_LABEL)); // Discard - primaryActions.push(this.instantiationService.createInstance(ExecuteCommandAction, REVERT_FILE_COMMAND_ID, nls.localize('discard', "Discard"))); + actions.primary!.push(this.instantiationService.createInstance(ExecuteCommandAction, REVERT_FILE_COMMAND_ID, nls.localize('discard', "Discard"))); // Message if (canHandlePermissionOrReadonlyErrors && isReadonly) { @@ -175,9 +174,8 @@ export class SaveErrorHandler extends Disposable implements ISaveErrorHandler, I } // Show message and keep function to hide in case the file gets saved/reverted - const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; const handle = this.notificationService.notify({ severity: Severity.Error, message, actions }); - Event.once(handle.onDidClose)(() => { dispose(primaryActions), dispose(secondaryActions); }); + Event.once(handle.onDidClose)(() => dispose(...actions.primary!, ...actions.secondary!)); this.messages.set(model.getResource(), handle); } @@ -255,16 +253,12 @@ class ResolveSaveConflictAction extends Action { } // Show additional help how to resolve the save conflict - const primaryActions: IAction[] = [ - this.instantiationService.createInstance(ResolveConflictLearnMoreAction) - ]; - const secondaryActions: IAction[] = [ - this.instantiationService.createInstance(DoNotShowResolveConflictLearnMoreAction) - ]; + const actions: INotificationActions = { primary: [], secondary: [] }; + actions.primary!.push(this.instantiationService.createInstance(ResolveConflictLearnMoreAction)); + actions.secondary!.push(this.instantiationService.createInstance(DoNotShowResolveConflictLearnMoreAction)); - const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; const handle = this.notificationService.notify({ severity: Severity.Info, message: conflictEditorHelp, actions }); - Event.once(handle.onDidClose)(() => { dispose(primaryActions); dispose(secondaryActions); }); + Event.once(handle.onDidClose)(() => dispose(...actions.primary!, ...actions.secondary!)); pendingResolveSaveConflictMessages.push(handle); } diff --git a/src/vs/workbench/contrib/files/browser/views/emptyView.ts b/src/vs/workbench/contrib/files/browser/views/emptyView.ts index 5885e6c1ed..9edc63a22f 100644 --- a/src/vs/workbench/contrib/files/browser/views/emptyView.ts +++ b/src/vs/workbench/contrib/files/browser/views/emptyView.ts @@ -5,12 +5,13 @@ import * as nls from 'vs/nls'; import * as errors from 'vs/base/common/errors'; +import * as env from 'vs/base/common/platform'; import * as DOM from 'vs/base/browser/dom'; import { IAction } from 'vs/base/common/actions'; import { Button } from 'vs/base/browser/ui/button/button'; import { IViewletViewOptions } from 'vs/workbench/browser/parts/views/viewsViewlet'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { OpenFolderAction, AddRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; +import { OpenFolderAction, OpenFileFolderAction, AddRootFolderAction } from 'vs/workbench/browser/actions/workspaceActions'; import { attachButtonStyler } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -68,11 +69,11 @@ export class EmptyView extends ViewletPanel { this.button = new Button(messageContainer); attachButtonStyler(this.button, this.themeService); - this._register(this.button.onDidClick(() => { + this.disposables.push(this.button.onDidClick(() => { if (!this.actionRunner) { return; } - const actionClass = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? AddRootFolderAction : OpenFolderAction; + const actionClass = this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE ? AddRootFolderAction : env.isMacintosh ? OpenFileFolderAction : OpenFolderAction; const action = this.instantiationService.createInstance(actionClass, actionClass.ID, actionClass.LABEL); this.actionRunner.run(action).then(() => { action.dispose(); @@ -82,7 +83,7 @@ export class EmptyView extends ViewletPanel { }); })); - this._register(new DragAndDropObserver(container, { + this.disposables.push(new DragAndDropObserver(container, { onDrop: e => { const color = this.themeService.getTheme().getColor(SIDE_BAR_BACKGROUND); container.style.backgroundColor = color ? color.toString() : ''; diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index 6c714650cf..13edb5fef1 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -9,17 +9,18 @@ import * as perf from 'vs/base/common/performance'; import { Action, IAction } from 'vs/base/common/actions'; import { memoize } from 'vs/base/common/decorators'; import { IFilesConfiguration, ExplorerFolderContext, FilesExplorerFocusedContext, ExplorerFocusedContext, ExplorerRootContext, ExplorerResourceReadonlyContext, IExplorerService, ExplorerResourceCut, ExplorerResourceMoveableToTrash } from 'vs/workbench/contrib/files/common/files'; -import { NewFolderAction, NewFileAction, FileCopiedContext, RefreshExplorerView, CollapseExplorerView } from 'vs/workbench/contrib/files/browser/fileActions'; +import { NewFolderAction, NewFileAction, FileCopiedContext, RefreshExplorerView } from 'vs/workbench/contrib/files/browser/fileActions'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput'; import * as DOM from 'vs/base/browser/dom'; +import { CollapseAction } from 'vs/workbench/browser/viewlet'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { ExplorerDecorationsProvider } from 'vs/workbench/contrib/files/browser/views/explorerDecorationsProvider'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ResourceContextKey } from 'vs/workbench/common/resources'; @@ -92,7 +93,7 @@ export class ExplorerView extends ViewletPanel { super({ ...(options as IViewletPanelOptions), id: ExplorerView.ID, ariaHeaderLabel: nls.localize('explorerSection', "Files Explorer Section") }, keybindingService, contextMenuService, configurationService); this.resourceContext = instantiationService.createInstance(ResourceContextKey); - this._register(this.resourceContext); + this.disposables.push(this.resourceContext); this.folderContext = ExplorerFolderContext.bindTo(contextKeyService); this.readonlyContext = ExplorerResourceReadonlyContext.bindTo(contextKeyService); this.rootContext = ExplorerRootContext.bindTo(contextKeyService); @@ -100,8 +101,8 @@ export class ExplorerView extends ViewletPanel { const decorationProvider = new ExplorerDecorationsProvider(this.explorerService, contextService); decorationService.registerDecorationsProvider(decorationProvider); - this._register(decorationProvider); - this._register(this.resourceContext); + this.disposables.push(decorationProvider); + this.disposables.push(this.resourceContext); } get name(): string { @@ -119,7 +120,7 @@ export class ExplorerView extends ViewletPanel { // Memoized locals @memoize private get contributedContextMenu(): IMenu { const contributedContextMenu = this.menuService.createMenu(MenuId.ExplorerContext, this.tree.contextKeyService); - this._register(contributedContextMenu); + this.disposables.push(contributedContextMenu); return contributedContextMenu; } @@ -147,8 +148,8 @@ export class ExplorerView extends ViewletPanel { titleElement.title = title; }; - this._register(this.contextService.onDidChangeWorkspaceName(setHeader)); - this._register(this.labelService.onDidChangeFormatters(setHeader)); + this.disposables.push(this.contextService.onDidChangeWorkspaceName(setHeader)); + this.disposables.push(this.labelService.onDidChangeFormatters(setHeader)); setHeader(); } @@ -164,13 +165,14 @@ export class ExplorerView extends ViewletPanel { this.toolbar.setActions(this.getActions(), this.getSecondaryActions())(); } - this._register(this.labelService.onDidChangeFormatters(() => { + this.disposables.push(this.labelService.onDidChangeFormatters(() => { this._onDidChangeTitleArea.fire(); + this.refresh(true); })); - this._register(this.explorerService.onDidChangeRoots(() => this.setTreeInput())); - this._register(this.explorerService.onDidChangeItem(e => this.refresh(e.recursive, e.item))); - this._register(this.explorerService.onDidChangeEditable(async e => { + this.disposables.push(this.explorerService.onDidChangeRoots(() => this.setTreeInput())); + this.disposables.push(this.explorerService.onDidChangeItem(e => this.refresh(e.recursive, e.item))); + this.disposables.push(this.explorerService.onDidChangeEditable(async e => { const isEditing = !!this.explorerService.getEditableData(e); if (isEditing) { @@ -188,22 +190,22 @@ export class ExplorerView extends ViewletPanel { this.tree.domFocus(); } })); - this._register(this.explorerService.onDidSelectResource(e => this.onSelectResource(e.resource, e.reveal))); - this._register(this.explorerService.onDidCopyItems(e => this.onCopyItems(e.items, e.cut, e.previouslyCutItems))); + this.disposables.push(this.explorerService.onDidSelectResource(e => this.onSelectResource(e.resource, e.reveal))); + this.disposables.push(this.explorerService.onDidCopyItems(e => this.onCopyItems(e.items, e.cut, e.previouslyCutItems))); // Update configuration const configuration = this.configurationService.getValue(); this.onConfigurationUpdated(configuration); // When the explorer viewer is loaded, listen to changes to the editor input - this._register(this.editorService.onDidActiveEditorChange(() => { + this.disposables.push(this.editorService.onDidActiveEditorChange(() => { this.selectActiveFile(true); })); // Also handle configuration updates - this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue(), e))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationUpdated(this.configurationService.getValue(), e))); - this._register(this.onDidChangeBodyVisibility(async visible => { + this.disposables.push(this.onDidChangeBodyVisibility(async visible => { if (visible) { // If a refresh was requested and we are now visible, run it if (this.shouldRefresh) { @@ -222,7 +224,7 @@ export class ExplorerView extends ViewletPanel { actions.push(this.instantiationService.createInstance(NewFileAction)); actions.push(this.instantiationService.createInstance(NewFolderAction)); actions.push(this.instantiationService.createInstance(RefreshExplorerView, RefreshExplorerView.ID, RefreshExplorerView.LABEL)); - actions.push(this.instantiationService.createInstance(CollapseExplorerView, CollapseExplorerView.ID, CollapseExplorerView.LABEL)); + actions.push(this.instantiationService.createInstance(CollapseAction, this.tree, true, 'explorer-action collapse-explorer')); return actions; } @@ -264,15 +266,15 @@ export class ExplorerView extends ViewletPanel { private createTree(container: HTMLElement): void { this.filter = this.instantiationService.createInstance(FilesFilter); - this._register(this.filter); + this.disposables.push(this.filter); const explorerLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); - this._register(explorerLabels); + this.disposables.push(explorerLabels); const updateWidth = (stat: ExplorerItem) => this.tree.updateWidth(stat); const filesRenderer = this.instantiationService.createInstance(FilesRenderer, explorerLabels, updateWidth); - this._register(filesRenderer); + this.disposables.push(filesRenderer); - this._register(createFileIconThemableTreeContainerScope(container, this.themeService)); + this.disposables.push(createFileIconThemableTreeContainerScope(container, this.themeService)); this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, container, new ExplorerDelegate(), [filesRenderer], this.instantiationService.createInstance(ExplorerDataSource), { @@ -302,19 +304,19 @@ export class ExplorerView extends ViewletPanel { dnd: this.instantiationService.createInstance(FileDragAndDrop), autoExpandSingleChildren: true }) as WorkbenchAsyncDataTree; - this._register(this.tree); + this.disposables.push(this.tree); // Bind context keys FilesExplorerFocusedContext.bindTo(this.tree.contextKeyService); ExplorerFocusedContext.bindTo(this.tree.contextKeyService); // Update resource context based on focused element - this._register(this.tree.onDidChangeFocus(e => this.onFocusChanged(e.elements))); + this.disposables.push(this.tree.onDidChangeFocus(e => this.onFocusChanged(e.elements))); this.onFocusChanged([]); const explorerNavigator = new TreeResourceNavigator2(this.tree); - this._register(explorerNavigator); + this.disposables.push(explorerNavigator); // Open when selecting via keyboard - this._register(explorerNavigator.onDidOpenResource(e => { + this.disposables.push(explorerNavigator.onDidOpenResource(e => { const selection = this.tree.getSelection(); // Do not react if the user is expanding selection via keyboard. // Check if the item was previously also selected, if yes the user is simply expanding / collapsing current selection #66589. @@ -337,12 +339,12 @@ export class ExplorerView extends ViewletPanel { } })); - this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); + this.disposables.push(this.tree.onContextMenu(e => this.onContextMenu(e))); // save view state on shutdown - this._register(this.storageService.onWillSaveState(() => { + this.storageService.onWillSaveState(() => { this.storageService.store(ExplorerView.TREE_VIEW_STATE_STORAGE_KEY, JSON.stringify(this.tree.getViewState()), StorageScope.WORKSPACE); - }, null)); + }, null, this.disposables); } // React on events @@ -367,21 +369,11 @@ export class ExplorerView extends ViewletPanel { } } - private setContextKeys(stat: ExplorerItem | null): void { - const isSingleFolder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER; - const resource = stat ? stat.resource : isSingleFolder ? this.contextService.getWorkspace().folders[0].uri : null; - this.resourceContext.set(resource); - this.folderContext.set((isSingleFolder && !stat) || !!stat && stat.isDirectory); - this.readonlyContext.set(!!stat && stat.isReadonly); - this.rootContext.set(!stat || (stat && stat.isRoot)); - } - private onContextMenu(e: ITreeContextMenuEvent): void { const stat = e.element; // update dynamic contexts this.fileCopiedContextKey.set(this.clipboardService.hasResources()); - this.setContextKeys(stat); const selection = this.tree.getSelection(); this.contextMenuService.showContextMenu({ @@ -406,8 +398,13 @@ export class ExplorerView extends ViewletPanel { } private onFocusChanged(elements: ExplorerItem[]): void { - const stat = elements && elements.length ? elements[0] : null; - this.setContextKeys(stat); + const stat = elements && elements.length ? elements[0] : undefined; + const isSingleFolder = this.contextService.getWorkbenchState() === WorkbenchState.FOLDER; + const resource = stat ? stat.resource : isSingleFolder ? this.contextService.getWorkspace().folders[0].uri : null; + this.resourceContext.set(resource); + this.folderContext.set((isSingleFolder && !stat) || !!stat && stat.isDirectory); + this.readonlyContext.set(!!stat && stat.isReadonly); + this.rootContext.set(!stat || (stat && stat.isRoot)); if (stat) { const enableTrash = this.configurationService.getValue().files.enableTrash; @@ -493,11 +490,7 @@ export class ExplorerView extends ViewletPanel { } }); - this.progressService.withProgress({ - location: ProgressLocation.Explorer, - delay: this.layoutService.isRestored() ? 800 : 1200 // less ugly initial startup - }, _progress => promise); - + this.progressService.showWhile(promise, this.layoutService.isRestored() ? 800 : 1200 /* less ugly initial startup */); return promise; } diff --git a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts index 0437444c78..fdad5d3b44 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerViewer.ts @@ -7,7 +7,7 @@ import { IAccessibilityProvider } from 'vs/base/browser/ui/list/listWidget'; import * as DOM from 'vs/base/browser/dom'; import * as glob from 'vs/base/common/glob'; import { IListVirtualDelegate, ListDragOverEffect } from 'vs/base/browser/ui/list/list'; -import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IFileService, FileKind, FileOperationError, FileOperationResult } from 'vs/platform/files/common/files'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -99,11 +99,7 @@ export class ExplorerDataSource implements IAsyncDataSource promise); - + this.progressService.showWhile(promise, this.layoutService.isRestored() ? 800 : 3200 /* less ugly initial startup */); return promise; } } @@ -222,19 +218,21 @@ export class FilesRenderer implements ITreeRenderer 0 && !stat.isDirectory ? lastDot : value.length }); - const done = once(async (success: boolean, finishEditing: boolean) => { + const done = once(async (success: boolean) => { label.element.style.display = 'none'; const value = inputBox.value; dispose(toDispose); container.removeChild(label.element); - if (finishEditing) { - // Timeout: once done rendering only then re-render #70902 - setTimeout(() => editableData.onFinish(value, success), 0); - } + // Timeout: once done rendering only then re-render #70902 + setTimeout(() => editableData.onFinish(value, success), 0); }); + let ignoreDisposeAndBlur = true; + setTimeout(() => ignoreDisposeAndBlur = false, 100); const blurDisposable = DOM.addDisposableListener(inputBox.inputElement, DOM.EventType.BLUR, () => { - done(inputBox.isInputValid(), true); + if (!ignoreDisposeAndBlur) { + done(inputBox.isInputValid()); + } }); const toDispose = [ @@ -242,10 +240,10 @@ export class FilesRenderer implements ITreeRenderer { if (e.equals(KeyCode.Enter)) { if (inputBox.validate()) { - done(true, true); + done(true); } } else if (e.equals(KeyCode.Escape)) { - done(false, true); + done(false); } }), blurDisposable, @@ -254,8 +252,10 @@ export class FilesRenderer implements ITreeRenderer { - blurDisposable.dispose(); - done(false, false); + if (!ignoreDisposeAndBlur) { + blurDisposable.dispose(); + done(false); + } }); } diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index 9e15a775d9..06dc9f65da 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -96,14 +96,14 @@ export class OpenEditorsView extends ViewletPanel { this.registerUpdateEvents(); // Also handle configuration updates - this._register(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(e))); + this.disposables.push(this.configurationService.onDidChangeConfiguration(e => this.onConfigurationChange(e))); // Handle dirty counter - this._register(this.untitledEditorService.onDidChangeDirty(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsDirty(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsSaved(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsSaveError(() => this.updateDirtyIndicator())); - this._register(this.textFileService.models.onModelsReverted(() => this.updateDirtyIndicator())); + this.disposables.push(this.untitledEditorService.onDidChangeDirty(() => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsDirty(() => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsSaved(() => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsSaveError(() => this.updateDirtyIndicator())); + this.disposables.push(this.textFileService.models.onModelsReverted(() => this.updateDirtyIndicator())); } private registerUpdateEvents(): void { @@ -163,16 +163,16 @@ export class OpenEditorsView extends ViewletPanel { } } })); - this._register(groupDisposables.get(group.id)!); + this.disposables.push(groupDisposables.get(group.id)!); }; this.editorGroupService.groups.forEach(g => addGroupListener(g)); - this._register(this.editorGroupService.onDidAddGroup(group => { + this.disposables.push(this.editorGroupService.onDidAddGroup(group => { addGroupListener(group); updateWholeList(); })); - this._register(this.editorGroupService.onDidMoveGroup(() => updateWholeList())); - this._register(this.editorGroupService.onDidRemoveGroup(group => { + this.disposables.push(this.editorGroupService.onDidMoveGroup(() => updateWholeList())); + this.disposables.push(this.editorGroupService.onDidRemoveGroup(group => { dispose(groupDisposables.get(group.id)); updateWholeList(); })); @@ -184,7 +184,7 @@ export class OpenEditorsView extends ViewletPanel { const count = dom.append(container, $('.count')); this.dirtyCountElement = dom.append(count, $('.monaco-count-badge')); - this._register((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { + this.disposables.push((attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { const background = colors.badgeBackground ? colors.badgeBackground.toString() : null; const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : null; const border = colors.contrastBorder ? colors.contrastBorder.toString() : null; @@ -220,11 +220,11 @@ export class OpenEditorsView extends ViewletPanel { identityProvider: { getId: (element: OpenEditor | IEditorGroup) => element instanceof OpenEditor ? element.getId() : element.id.toString() }, dnd: new OpenEditorsDragAndDrop(this.instantiationService, this.editorGroupService) }) as WorkbenchList; - this._register(this.list); - this._register(this.listLabels); + this.disposables.push(this.list); + this.disposables.push(this.listLabels); this.contributedContextMenu = this.menuService.createMenu(MenuId.OpenEditorsContext, this.list.contextKeyService); - this._register(this.contributedContextMenu); + this.disposables.push(this.contributedContextMenu); this.updateSize(); @@ -233,11 +233,11 @@ export class OpenEditorsView extends ViewletPanel { ExplorerFocusedContext.bindTo(this.list.contextKeyService); this.resourceContext = this.instantiationService.createInstance(ResourceContextKey); - this._register(this.resourceContext); + this.disposables.push(this.resourceContext); this.groupFocusedContext = OpenEditorsGroupContext.bindTo(this.contextKeyService); this.dirtyEditorFocusedContext = DirtyEditorContext.bindTo(this.contextKeyService); - this._register(this.list.onContextMenu(e => this.onListContextMenu(e))); + this.disposables.push(this.list.onContextMenu(e => this.onListContextMenu(e))); this.list.onFocusChange(e => { this.resourceContext.reset(); this.groupFocusedContext.reset(); @@ -252,12 +252,12 @@ export class OpenEditorsView extends ViewletPanel { }); // Open when selecting via keyboard - this._register(this.list.onMouseMiddleClick(e => { + this.disposables.push(this.list.onMouseMiddleClick(e => { if (e && e.element instanceof OpenEditor) { e.element.group.closeEditor(e.element.editor, { preserveFocus: true }); } })); - this._register(this.list.onDidOpen(e => { + this.disposables.push(this.list.onDidOpen(e => { const browserEvent = e.browserEvent; let openToSide = false; @@ -280,7 +280,7 @@ export class OpenEditorsView extends ViewletPanel { this.listRefreshScheduler.schedule(0); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && this.needsRefresh) { this.listRefreshScheduler.schedule(0); } diff --git a/src/vs/workbench/contrib/files/common/explorerModel.ts b/src/vs/workbench/contrib/files/common/explorerModel.ts index 5ccaa5c279..67af5d3cc8 100644 --- a/src/vs/workbench/contrib/files/common/explorerModel.ts +++ b/src/vs/workbench/contrib/files/common/explorerModel.ts @@ -243,23 +243,27 @@ export class ExplorerItem { return this.children.get(this.getPlatformAwareName(name)); } - async fetchChildren(fileService: IFileService, explorerService: IExplorerService): Promise { + fetchChildren(fileService: IFileService, explorerService: IExplorerService): Promise { + let promise: Promise = Promise.resolve(undefined); if (!this._isDirectoryResolved) { // Resolve metadata only when the mtime is needed since this can be expensive // Mtime is only used when the sort order is 'modified' const resolveMetadata = explorerService.sortOrder === 'modified'; - const stat = await fileService.resolve(this.resource, { resolveSingleChildDescendants: true, resolveMetadata }); - const resolved = ExplorerItem.create(stat, this); - ExplorerItem.mergeLocalWithDisk(resolved, this); - this._isDirectoryResolved = true; + promise = fileService.resolve(this.resource, { resolveSingleChildDescendants: true, resolveMetadata }).then(stat => { + const resolved = ExplorerItem.create(stat, this); + ExplorerItem.mergeLocalWithDisk(resolved, this); + this._isDirectoryResolved = true; + }); } - const items: ExplorerItem[] = []; - this.children.forEach(child => { - items.push(child); - }); + return promise.then(() => { + const items: ExplorerItem[] = []; + this.children.forEach(child => { + items.push(child); + }); - return items; + return items; + }); } /** diff --git a/src/vs/workbench/contrib/files/common/explorerService.ts b/src/vs/workbench/contrib/files/common/explorerService.ts index f4633a246b..45da0cdab0 100644 --- a/src/vs/workbench/contrib/files/common/explorerService.ts +++ b/src/vs/workbench/contrib/files/common/explorerService.ts @@ -147,7 +147,7 @@ export class ExplorerService implements IExplorerService { return !!this.editable && (this.editable.stat === stat || !stat); } - async select(resource: URI, reveal?: boolean): Promise { + select(resource: URI, reveal?: boolean): Promise { const fileStat = this.findClosest(resource); if (fileStat) { this._onDidSelectResource.fire({ resource: fileStat.resource, reveal }); @@ -159,9 +159,7 @@ export class ExplorerService implements IExplorerService { const workspaceFolder = this.contextService.getWorkspaceFolder(resource); const rootUri = workspaceFolder ? workspaceFolder.uri : this.roots[0].resource; const root = this.roots.filter(r => r.resource.toString() === rootUri.toString()).pop()!; - - try { - const stat = await this.fileService.resolve(rootUri, options); + return this.fileService.resolve(rootUri, options).then(stat => { // Convert to model const modelStat = ExplorerItem.create(stat, undefined, options.resolveTo); @@ -172,19 +170,17 @@ export class ExplorerService implements IExplorerService { // Select and Reveal this._onDidSelectResource.fire({ resource: item ? item.resource : undefined, reveal }); - } catch (error) { + }, () => { root.isError = true; this._onDidChangeItem.fire({ item: root, recursive: false }); - } + }); } refresh(): void { this.model.roots.forEach(r => r.forgetChildren()); this._onDidChangeItem.fire({ recursive: true }); const resource = this.editorService.activeEditor ? this.editorService.activeEditor.getResource() : undefined; - const autoReveal = this.configurationService.getValue().explorer.autoReveal; - - if (resource && autoReveal) { + if (resource) { // We did a top level refresh, reveal the active file #67118 this.select(resource, true); } @@ -285,7 +281,7 @@ export class ExplorerService implements IExplorerService { if (added.length) { // Check added: Refresh if added file/folder is not part of resolved root and parent is part of it - const ignoredPaths: Set = new Set(); + const ignoredPaths: { [resource: string]: boolean } = <{ [resource: string]: boolean }>{}; for (let i = 0; i < added.length; i++) { const change = added[i]; @@ -293,7 +289,7 @@ export class ExplorerService implements IExplorerService { const parent = dirname(change.resource); // Continue if parent was already determined as to be ignored - if (ignoredPaths.has(parent.toString())) { + if (ignoredPaths[parent.toString()]) { continue; } @@ -305,7 +301,7 @@ export class ExplorerService implements IExplorerService { // Keep track of path that can be ignored for faster lookup if (!parentStat || !parentStat.isDirectoryResolved) { - ignoredPaths.add(parent.toString()); + ignoredPaths[parent.toString()] = true; } } } diff --git a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts index 801c4423fa..bc8199aa45 100644 --- a/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts +++ b/src/vs/workbench/contrib/format/browser/formatActionsMultiple.ts @@ -26,6 +26,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { ITextModel } from 'vs/editor/common/model'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IModeService } from 'vs/editor/common/services/modeService'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -45,6 +46,7 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { @INotificationService private readonly _notificationService: INotificationService, @IQuickInputService private readonly _quickInputService: IQuickInputService, @IModeService private readonly _modeService: IModeService, + @IStatusbarService private readonly _statusbarService: IStatusbarService, @ILabelService private readonly _labelService: ILabelService, ) { super(); @@ -95,7 +97,7 @@ class DefaultFormatter extends Disposable implements IWorkbenchContribution { // formatter does not target this file const label = this._labelService.getUriLabel(document.uri, { relative: true }); const message = nls.localize('miss', "Extension '{0}' cannot format '{1}'", extension.displayName || extension.name, label); - this._notificationService.status(message, { hideAfter: 4000 }); + this._statusbarService.setStatusMessage(message, 4000); return undefined; } } else if (formatter.length === 1) { diff --git a/src/vs/workbench/contrib/logs/common/logs.contribution.ts b/src/vs/workbench/contrib/logs/common/logs.contribution.ts index 33534fb324..b15e07315f 100644 --- a/src/vs/workbench/contrib/logs/common/logs.contribution.ts +++ b/src/vs/workbench/contrib/logs/common/logs.contribution.ts @@ -17,30 +17,28 @@ import { IWorkbenchActionRegistry, Extensions as WorkbenchActionExtensions } fro import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { OpenLogsFolderAction, SetLogLevelAction } from 'vs/workbench/contrib/logs/common/logsActions'; import { ILogService, LogLevel } from 'vs/platform/log/common/log'; -import { IFileService, FileChangeType } from 'vs/platform/files/common/files'; -import { dirname } from 'vs/base/common/resources'; class LogOutputChannels extends Disposable implements IWorkbenchContribution { constructor( @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @ILogService logService: ILogService, - @IFileService private readonly fileService: IFileService + @ILogService logService: ILogService ) { super(); - this.registerLogChannel(Constants.mainLogChannelId, nls.localize('mainLog', "Main"), URI.file(join(environmentService.logsPath, `main.log`))); - this.registerLogChannel(Constants.sharedLogChannelId, nls.localize('sharedLog', "Shared"), URI.file(join(environmentService.logsPath, `sharedprocess.log`))); - this.registerLogChannel(Constants.rendererLogChannelId, nls.localize('rendererLog', "Window"), URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`))); + let outputChannelRegistry = Registry.as(OutputExt.OutputChannels); + outputChannelRegistry.registerChannel({ id: Constants.mainLogChannelId, label: nls.localize('mainLog', "Main"), file: URI.file(join(environmentService.logsPath, `main.log`)), log: true }); + outputChannelRegistry.registerChannel({ id: Constants.sharedLogChannelId, label: nls.localize('sharedLog', "Shared"), file: URI.file(join(environmentService.logsPath, `sharedprocess.log`)), log: true }); + outputChannelRegistry.registerChannel({ id: Constants.rendererLogChannelId, label: nls.localize('rendererLog', "Window"), file: URI.file(join(environmentService.logsPath, `renderer${environmentService.configuration.windowId}.log`)), log: true }); // {{SQL CARBON EDIT}} @anthonydresser 05/19/19 investigate, this should be in the extension let toolsServiceLogFile: string = join(environmentService.logsPath, '..', '..', 'mssql', `sqltools_${Date.now()}.log`); console.log(`SqlTools Log file is: ${toolsServiceLogFile}`); - this.registerLogChannel(Constants.sqlToolsLogChannellId, nls.localize('sqlToolsLog', "Log (SqlTools)"), URI.file(toolsServiceLogFile)); + outputChannelRegistry.registerChannel({ id: Constants.sqlToolsLogChannellId, label: nls.localize('sqlToolsLog', "Log (SqlTools)"), file: URI.file(toolsServiceLogFile), log: true }); // {{SQL CARBON EDIT}} - End const registerTelemetryChannel = (level: LogLevel) => { - if (level === LogLevel.Trace && !Registry.as(OutputExt.OutputChannels).getChannel(Constants.telemetryLogChannelId)) { - this.registerLogChannel(Constants.telemetryLogChannelId, nls.localize('telemetryLog', "Telemetry"), URI.file(join(environmentService.logsPath, `telemetry.log`))); + if (level === LogLevel.Trace && !outputChannelRegistry.getChannel(Constants.telemetryLogChannelId)) { + outputChannelRegistry.registerChannel({ id: Constants.telemetryLogChannelId, label: nls.localize('telemetryLog', "Telemetry"), file: URI.file(join(environmentService.logsPath, `telemetry.log`)), log: true }); } }; registerTelemetryChannel(logService.getLevel()); @@ -51,25 +49,6 @@ class LogOutputChannels extends Disposable implements IWorkbenchContribution { workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(OpenLogsFolderAction, OpenLogsFolderAction.ID, OpenLogsFolderAction.LABEL), 'Developer: Open Log Folder', devCategory); workbenchActionsRegistry.registerWorkbenchAction(new SyncActionDescriptor(SetLogLevelAction, SetLogLevelAction.ID, SetLogLevelAction.LABEL), 'Developer: Set Log Level', devCategory); } - - private async registerLogChannel(id: string, label: string, file: URI): Promise { - const outputChannelRegistry = Registry.as(OutputExt.OutputChannels); - const exists = await this.fileService.exists(file); - if (exists) { - outputChannelRegistry.registerChannel({ id, label, file, log: true }); - return; - } - - const watcher = this.fileService.watch(dirname(file)); - const disposable = this.fileService.onFileChanges(e => { - if (e.contains(file, FileChangeType.ADDED)) { - watcher.dispose(); - disposable.dispose(); - outputChannelRegistry.registerChannel({ id, label, file, log: true }); - } - }); - } - } -Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Restored); +Registry.as(WorkbenchExtensions.Workbench).registerWorkbenchContribution(LogOutputChannels, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts index 44a427b079..3efc323eed 100644 --- a/src/vs/workbench/contrib/markers/browser/markers.contribution.ts +++ b/src/vs/workbench/contrib/markers/browser/markers.contribution.ts @@ -19,16 +19,12 @@ import { Registry } from 'vs/platform/registry/common/platform'; import { ToggleMarkersPanelAction, ShowProblemsPanelAction } from 'vs/workbench/contrib/markers/browser/markersPanelActions'; import Constants from 'vs/workbench/contrib/markers/browser/constants'; import Messages from 'vs/workbench/contrib/markers/browser/messages'; -import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } from 'vs/workbench/common/contributions'; import { IMarkersWorkbenchService, MarkersWorkbenchService, ActivityUpdater } from 'vs/workbench/contrib/markers/browser/markers'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { ActivePanelContext } from 'vs/workbench/common/panel'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IStatusbarEntryAccessor, IStatusbarService, StatusbarAlignment, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; -import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; -import { CommandsRegistry } from 'vs/platform/commands/common/commands'; registerSingleton(IMarkersWorkbenchService, MarkersWorkbenchService, false); @@ -257,86 +253,3 @@ MenuRegistry.appendMenuItem(MenuId.MenubarViewMenu, { }, order: 4 }); - -CommandsRegistry.registerCommand('workbench.actions.view.toggleProblems', accessor => { - const panelService = accessor.get(IPanelService); - const panel = accessor.get(IPanelService).getActivePanel(); - if (panel && panel.getId() === Constants.MARKERS_PANEL_ID) { - panelService.hideActivePanel(); - } else { - panelService.openPanel(Constants.MARKERS_PANEL_ID, true); - } -}); - -class MarkersStatusBarContributions extends Disposable implements IWorkbenchContribution { - - private markersStatusItem: IStatusbarEntryAccessor; - - constructor( - @IMarkerService private readonly markerService: IMarkerService, - @IStatusbarService private readonly statusbarService: IStatusbarService - ) { - super(); - this.markersStatusItem = this._register(this.statusbarService.addEntry(this.getMarkersItem(), 'status.problems', localize('status.problems', "Problems"), StatusbarAlignment.LEFT, 50 /* Medium Priority */)); - this.markerService.onMarkerChanged(() => this.markersStatusItem.update(this.getMarkersItem())); - } - - private getMarkersItem(): IStatusbarEntry { - const markersStatistics = this.markerService.getStatistics(); - return { - text: this.getMarkersText(markersStatistics), - tooltip: this.getMarkersTooltip(markersStatistics), - command: 'workbench.actions.view.toggleProblems' - }; - } - - private getMarkersTooltip(stats: MarkerStatistics): string { - const errorTitle = (n: number) => localize('totalErrors', "{0} Errors", n); - const warningTitle = (n: number) => localize('totalWarnings', "{0} Warnings", n); - const infoTitle = (n: number) => localize('totalInfos', "{0} Infos", n); - - const titles: string[] = []; - - if (stats.errors > 0) { - titles.push(errorTitle(stats.errors)); - } - - if (stats.warnings > 0) { - titles.push(warningTitle(stats.warnings)); - } - - if (stats.infos > 0) { - titles.push(infoTitle(stats.infos)); - } - - if (titles.length === 0) { - return localize('noProblems', "No Problems"); - } - - return titles.join(', '); - } - - private getMarkersText(stats: MarkerStatistics): string { - const problemsText: string[] = []; - - // Errors - problemsText.push('$(error) ' + this.packNumber(stats.errors)); - - // Warnings - problemsText.push('$(warning) ' + this.packNumber(stats.warnings)); - - // Info (only if any) - if (stats.infos > 0) { - problemsText.push('$(info) ' + this.packNumber(stats.infos)); - } - - return problemsText.join(' '); - } - - private packNumber(n: number): string { - const manyProblems = localize('manyProblems', "10K+"); - return n > 9999 ? manyProblems : n > 999 ? n.toString().charAt(0) + 'K' : n.toString(); - } -} - -workbenchRegistry.registerWorkbenchContribution(MarkersStatusBarContributions, LifecyclePhase.Restored); \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index c22e5c0ea6..08555275ac 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -44,7 +44,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ResourceLabels } from 'vs/workbench/browser/labels'; import { IMarker } from 'vs/platform/markers/common/markers'; import { withUndefinedAsNull } from 'vs/base/common/types'; -import { MementoObject } from 'vs/workbench/common/memento'; function createModelIterator(model: MarkersModel): Iterator> { const resourcesIt = Iterator.fromArray(model.resourceMarkers); @@ -80,12 +79,12 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { private treeContainer: HTMLElement; private messageBoxContainer: HTMLElement; private ariaLabelElement: HTMLElement; - private readonly panelState: MementoObject; + private panelState: object; private panelFoucusContextKey: IContextKey; private filter: Filter; - private _onDidFilter = this._register(new Emitter()); + private _onDidFilter = new Emitter(); readonly onDidFilter: Event = this._onDidFilter.event; private cachedFilterStats: { total: number; filtered: number; } | undefined = undefined; @@ -163,11 +162,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { return; } - if (this.isEmpty()) { - this.messageBoxContainer.focus(); - } else { - this.tree.getHTMLElement().focus(); - } + this.tree.getHTMLElement().focus(); } public focusFilter(): void { @@ -353,7 +348,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } })); - this._register(this.tree.onContextMenu(this.onContextMenu, this)); + this.tree.onContextMenu(this.onContextMenu, this, this._toDispose); this._register(this.configurationService.onDidChangeConfiguration(e => { if (this.filterAction.useFilesExclude && e.affectsConfiguration('files.exclude')) { @@ -475,15 +470,11 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { } } - private isEmpty(): boolean { - const { total, filtered } = this.getFilterStats(); - return total === 0 || filtered === 0; - } - private render(): void { this.cachedFilterStats = undefined; this.tree.setChildren(null, createModelIterator(this.markersWorkbenchService.markersModel)); - dom.toggleClass(this.treeContainer, 'hidden', this.isEmpty()); + const { total, filtered } = this.getFilterStats(); + dom.toggleClass(this.treeContainer, 'hidden', total === 0 || filtered === 0); this.renderMessage(); } diff --git a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts index f495beb415..a2a4026869 100644 --- a/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts +++ b/src/vs/workbench/contrib/markers/browser/markersTreeViewer.ts @@ -43,7 +43,6 @@ import { IBulkEditService } from 'vs/editor/browser/services/bulkEditService'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IEditorService, ACTIVE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { applyCodeAction } from 'vs/editor/contrib/codeAction/codeActionCommands'; -import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; export type TreeElement = ResourceMarkers | Marker | RelatedInformation; @@ -256,7 +255,7 @@ class MarkerWidget extends Disposable { this.actionBar = this._register(new ActionBar(dom.append(parent, dom.$('.actions')), { actionViewItemProvider: (action) => action.id === QuickFixAction.ID ? instantiationService.createInstance(QuickFixActionViewItem, action) : undefined })); - this.icon = dom.append(parent, dom.$('')); + this.icon = dom.append(parent, dom.$('.icon')); this.multilineActionbar = this._register(new ActionBar(dom.append(parent, dom.$('.multiline-actions')))); this.messageAndDetailsContainer = dom.append(parent, dom.$('.marker-message-details')); this._register(toDisposable(() => this.disposables = dispose(this.disposables))); @@ -270,7 +269,7 @@ class MarkerWidget extends Disposable { } dom.clearNode(this.messageAndDetailsContainer); - this.icon.className = `marker-icon ${SeverityIcon.className(MarkerSeverity.toSeverity(element.marker.severity))}`; + this.icon.className = 'marker-icon ' + MarkerWidget.iconClassNameFor(element.marker); this.renderQuickfixActionbar(element); this.renderMultilineActionbar(element); @@ -346,6 +345,20 @@ class MarkerWidget extends Disposable { const lnCol = dom.append(parent, dom.$('span.marker-line')); lnCol.textContent = Messages.MARKERS_PANEL_AT_LINE_COL_NUMBER(marker.startLineNumber, marker.startColumn); } + + private static iconClassNameFor(element: IMarker): string { + switch (element.severity) { + case MarkerSeverity.Hint: + return 'info'; + case MarkerSeverity.Info: + return 'info'; + case MarkerSeverity.Warning: + return 'warning'; + case MarkerSeverity.Error: + return 'error'; + } + return ''; + } } export class RelatedInformationRenderer implements ITreeRenderer { @@ -548,9 +561,7 @@ export class MarkerViewModel extends Disposable { if (model) { if (!this.codeActionsPromise) { this.codeActionsPromise = createCancelablePromise(cancellationToken => { - return getCodeActions(model, new Range(this.marker.range.startLineNumber, this.marker.range.startColumn, this.marker.range.endLineNumber, this.marker.range.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken).then(actions => { - return this._register(actions); - }); + return getCodeActions(model, new Range(this.marker.range.startLineNumber, this.marker.range.startColumn, this.marker.range.endLineNumber, this.marker.range.endColumn), { type: 'manual', filter: { kind: CodeActionKind.QuickFix } }, cancellationToken); }); } return this.codeActionsPromise; diff --git a/src/vs/workbench/contrib/markers/browser/media/markers.css b/src/vs/workbench/contrib/markers/browser/media/markers.css index 0d725b51a4..7ea45538c7 100644 --- a/src/vs/workbench/contrib/markers/browser/media/markers.css +++ b/src/vs/workbench/contrib/markers/browser/media/markers.css @@ -160,6 +160,31 @@ .markers-panel .monaco-tl-contents .marker-icon { height: 22px; + width: 16px; +} + +.markers-panel .marker-icon.warning { + background: url('status-warning.svg') center center no-repeat; +} + +.markers-panel .marker-icon.error { + background: url('status-error.svg') center center no-repeat; +} + +.markers-panel .marker-icon.info { + background: url('status-info.svg') center center no-repeat; +} + +.vs-dark .markers-panel .marker-icon.warning { + background: url('status-warning-inverse.svg') center center no-repeat; +} + +.vs-dark .markers-panel .marker-icon.error { + background: url('status-error-inverse.svg') center center no-repeat; +} + +.vs-dark .markers-panel .marker-icon.info { + background: url('status-info-inverse.svg') center center no-repeat; } .markers-panel .monaco-tl-contents .actions .action-label.icon.markers-panel-action-quickfix { diff --git a/src/vs/workbench/contrib/markers/browser/media/status-error-inverse.svg b/src/vs/workbench/contrib/markers/browser/media/status-error-inverse.svg new file mode 100644 index 0000000000..3c852a7ffd --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-error-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/media/status-error.svg b/src/vs/workbench/contrib/markers/browser/media/status-error.svg new file mode 100644 index 0000000000..a1ddb39fed --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/media/status-info-inverse.svg b/src/vs/workbench/contrib/markers/browser/media/status-info-inverse.svg new file mode 100644 index 0000000000..d38c363e0e --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-info-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/media/status-info.svg b/src/vs/workbench/contrib/markers/browser/media/status-info.svg new file mode 100644 index 0000000000..6e2e22f67b --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/media/status-warning-inverse.svg b/src/vs/workbench/contrib/markers/browser/media/status-warning-inverse.svg new file mode 100644 index 0000000000..df44e61b32 --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-warning-inverse.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/media/status-warning.svg b/src/vs/workbench/contrib/markers/browser/media/status-warning.svg new file mode 100644 index 0000000000..f4e2a84b0a --- /dev/null +++ b/src/vs/workbench/contrib/markers/browser/media/status-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/markers/browser/messages.ts b/src/vs/workbench/contrib/markers/browser/messages.ts index 4e7c54e36c..1051269458 100644 --- a/src/vs/workbench/contrib/markers/browser/messages.ts +++ b/src/vs/workbench/contrib/markers/browser/messages.ts @@ -28,7 +28,7 @@ export default class Messages { public static MARKERS_PANEL_ACTION_TOOLTIP_FILTER: string = nls.localize('markers.panel.action.filter', "Filter Problems"); public static MARKERS_PANEL_ACTION_TOOLTIP_QUICKFIX: string = nls.localize('markers.panel.action.quickfix', "Show fixes"); public static MARKERS_PANEL_FILTER_ARIA_LABEL: string = nls.localize('markers.panel.filter.ariaLabel', "Filter Problems"); - public static MARKERS_PANEL_FILTER_PLACEHOLDER: string = nls.localize('markers.panel.filter.placeholder', "Filter. E.g.: text, **/*.ts, !**/node_modules/**"); + public static MARKERS_PANEL_FILTER_PLACEHOLDER: string = nls.localize('markers.panel.filter.placeholder', "Filter. Eg: text, **/*.ts, !**/node_modules/**"); public static MARKERS_PANEL_FILTER_ERRORS: string = nls.localize('markers.panel.filter.errors', "errors"); public static MARKERS_PANEL_FILTER_WARNINGS: string = nls.localize('markers.panel.filter.warnings', "warnings"); public static MARKERS_PANEL_FILTER_INFOS: string = nls.localize('markers.panel.filter.infos', "infos"); diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 7301dc8b50..db8ee42436 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -304,7 +304,7 @@ export class OutlinePanel extends ViewletPanel { this._inputContainer = dom.$('.outline-input'); this._progressBar = new ProgressBar(progressContainer); - this._register(attachProgressBarStyler(this._progressBar, this._themeService)); + this.disposables.push(attachProgressBarStyler(this._progressBar, this._themeService)); let treeContainer = dom.$('.outline-tree'); dom.append( @@ -340,13 +340,13 @@ export class OutlinePanel extends ViewletPanel { }); // feature: filter on type - keep tree and menu in sync - this._register(this._tree.onDidUpdateOptions(e => { + this.disposables.push(this._tree.onDidUpdateOptions(e => { this._outlineViewState.filterOnType = Boolean(e.filterOnType); })); // feature: expand all nodes when filtering (not when finding) let viewState: IDataTreeViewState | undefined; - this._register(this._tree.onDidChangeTypeFilterPattern(pattern => { + this.disposables.push(this._tree.onDidChangeTypeFilterPattern(pattern => { if (!this._tree.options.filterOnType) { return; } @@ -360,13 +360,13 @@ export class OutlinePanel extends ViewletPanel { })); // feature: toggle icons - this._register(this._configurationService.onDidChangeConfiguration(e => { + this.disposables.push(this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(OutlineConfigKeys.icons)) { this._tree.updateChildren(); } })); - this._register(this.onDidChangeBodyVisibility(visible => { + this.disposables.push(this.onDidChangeBodyVisibility(visible => { if (visible && !this._requestOracle) { this._requestOracle = this._instantiationService.createInstance(RequestOracle, (editor: ICodeEditor | undefined, event: IModelContentChangedEvent | undefined) => this._doUpdate(editor, event), DocumentSymbolProviderRegistry); } else if (!visible) { @@ -390,21 +390,20 @@ export class OutlinePanel extends ViewletPanel { } getSecondaryActions(): IAction[] { - const group = this._register(new RadioGroup([ + let group = new RadioGroup([ new SimpleToggleAction(this._outlineViewState, localize('sortByPosition', "Sort By: Position"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByPosition, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByPosition), new SimpleToggleAction(this._outlineViewState, localize('sortByName', "Sort By: Name"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByName, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByName), new SimpleToggleAction(this._outlineViewState, localize('sortByKind', "Sort By: Type"), () => this._outlineViewState.sortBy === OutlineSortOrder.ByKind, _ => this._outlineViewState.sortBy = OutlineSortOrder.ByKind), - ])); - const result = [ + ]); + let result = [ new SimpleToggleAction(this._outlineViewState, localize('followCur', "Follow Cursor"), () => this._outlineViewState.followCursor, action => this._outlineViewState.followCursor = action.checked), new SimpleToggleAction(this._outlineViewState, localize('filterOnType', "Filter on Type"), () => this._outlineViewState.filterOnType, action => this._outlineViewState.filterOnType = action.checked), new Separator(), ...group.actions, ]; - for (const r of result) { - this._register(r); - } + this.disposables.push(...result); + this.disposables.push(group); return result; } diff --git a/src/vs/workbench/contrib/output/browser/outputActions.ts b/src/vs/workbench/contrib/output/browser/outputActions.ts index 1f0283df9a..cd2e5cac4e 100644 --- a/src/vs/workbench/contrib/output/browser/outputActions.ts +++ b/src/vs/workbench/contrib/output/browser/outputActions.ts @@ -141,10 +141,10 @@ export class SwitchOutputActionViewItem extends SelectActionViewItem { super(null, action, [], 0, contextViewService, { ariaLabel: nls.localize('outputChannels', 'Output Channels.') }); let outputChannelRegistry = Registry.as(OutputExt.OutputChannels); - this._register(outputChannelRegistry.onDidRegisterChannel(() => this.updateOtions())); - this._register(outputChannelRegistry.onDidRemoveChannel(() => this.updateOtions())); - this._register(this.outputService.onActiveOutputChannel(() => this.updateOtions())); - this._register(attachSelectBoxStyler(this.selectBox, themeService)); + this.toDispose.push(outputChannelRegistry.onDidRegisterChannel(() => this.updateOtions())); + this.toDispose.push(outputChannelRegistry.onDidRemoveChannel(() => this.updateOtions())); + this.toDispose.push(this.outputService.onActiveOutputChannel(() => this.updateOtions())); + this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService)); this.updateOtions(); } diff --git a/src/vs/workbench/contrib/output/browser/outputServices.ts b/src/vs/workbench/contrib/output/browser/outputServices.ts index de0fadca75..42466560e3 100644 --- a/src/vs/workbench/contrib/output/browser/outputServices.ts +++ b/src/vs/workbench/contrib/output/browser/outputServices.ts @@ -68,7 +68,7 @@ export class OutputService extends Disposable implements IOutputService, ITextMo private activeChannelIdInStorage: string; private activeChannel?: OutputChannel; - private readonly _onActiveOutputChannel = this._register(new Emitter()); + private readonly _onActiveOutputChannel = new Emitter(); readonly onActiveOutputChannel: Event = this._onActiveOutputChannel.event; private _outputPanel: OutputPanel; diff --git a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts index 1a86f4e6d1..cc5ae90899 100644 --- a/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts +++ b/src/vs/workbench/contrib/performance/electron-browser/perfviewEditor.ts @@ -20,6 +20,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService'; import { writeTransientState } from 'vs/workbench/contrib/codeEditor/browser/toggleWordWrap'; import { mergeSort } from 'vs/base/common/arrays'; +import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import product from 'vs/platform/product/node/product'; import pkg from 'vs/platform/product/node/package'; @@ -72,6 +73,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { @ICodeEditorService private readonly _editorService: ICodeEditorService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @ITimerService private readonly _timerService: ITimerService, + @IEnvironmentService private readonly _envService: IEnvironmentService, @IExtensionService private readonly _extensionService: IExtensionService, ) { } @@ -105,7 +107,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { ]).then(([metrics]) => { if (this._model && !this._model.isDisposed()) { - let stats = LoaderStats.get(); + let stats = this._envService.args['prof-modules'] ? LoaderStats.get() : undefined; let md = new MarkdownBuilder(); this._addSummary(md, metrics); md.blank(); @@ -116,8 +118,6 @@ class PerfModelContentProvider implements ITextModelContentProvider { this._addRawPerfMarks(md); md.blank(); this._addLoaderStats(md, stats); - md.blank(); - this._addCachedDataStats(md); this._model.setValue(md.value); } @@ -136,7 +136,7 @@ class PerfModelContentProvider implements ITextModelContentProvider { md.li(`Memory(System): ${(metrics.totalmem / (1024 * 1024 * 1024)).toFixed(2)} GB(${(metrics.freemem / (1024 * 1024 * 1024)).toFixed(2)}GB free)`); } if (metrics.meminfo) { - md.li(`Memory(Process): ${(metrics.meminfo.workingSetSize / 1024).toFixed(2)} MB working set(${(metrics.meminfo.privateBytes / 1024).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / 1024).toFixed(2)}MB shared)`); + md.li(`Memory(Process): ${(metrics.meminfo.workingSetSize / 1024).toFixed(2)} MB working set(${(metrics.meminfo.peakWorkingSetSize / 1024).toFixed(2)}MB peak, ${(metrics.meminfo.privateBytes / 1024).toFixed(2)}MB private, ${(metrics.meminfo.sharedBytes / 1024).toFixed(2)}MB shared)`); } md.li(`VM(likelyhood): ${metrics.isVMLikelyhood}%`); md.li(`Initial Startup: ${metrics.initialStartup}`); @@ -210,54 +210,21 @@ class PerfModelContentProvider implements ITextModelContentProvider { md.value += '```\n'; } - private _addLoaderStats(md: MarkdownBuilder, stats: LoaderStats): void { - md.heading(2, 'Loader Stats'); - md.heading(3, 'Load AMD-module'); - md.table(['Module', 'Duration'], stats.amdLoad); - md.blank(); - md.heading(3, 'Load commonjs-module'); - md.table(['Module', 'Duration'], stats.nodeRequire); - md.blank(); - md.heading(3, 'Invoke AMD-module factory'); - md.table(['Module', 'Duration'], stats.amdInvoke); - md.blank(); - md.heading(3, 'Invoke commonjs-module'); - md.table(['Module', 'Duration'], stats.nodeEval); - } - - private _addCachedDataStats(md: MarkdownBuilder): void { - - const map = new Map(); - map.set(LoaderEventType.CachedDataCreated, []); - map.set(LoaderEventType.CachedDataFound, []); - map.set(LoaderEventType.CachedDataMissed, []); - map.set(LoaderEventType.CachedDataRejected, []); - for (const stat of require.getStats()) { - if (map.has(stat.type)) { - map.get(stat.type)!.push(stat.detail); - } + private _addLoaderStats(md: MarkdownBuilder, stats?: LoaderStats): void { + if (stats) { + md.heading(2, 'Loader Stats'); + md.heading(3, 'Load AMD-module'); + md.table(['Module', 'Duration'], stats.amdLoad); + md.blank(); + md.heading(3, 'Load commonjs-module'); + md.table(['Module', 'Duration'], stats.nodeRequire); + md.blank(); + md.heading(3, 'Invoke AMD-module factory'); + md.table(['Module', 'Duration'], stats.amdInvoke); + md.blank(); + md.heading(3, 'Invoke commonjs-module'); + md.table(['Module', 'Duration'], stats.nodeEval); } - - const printLists = (arr?: string[]) => { - if (arr) { - arr.sort(); - for (const e of arr) { - md.li(`${e}`); - } - md.blank(); - } - }; - - md.heading(2, 'Node Cached Data Stats'); - md.blank(); - md.heading(3, 'cached data used'); - printLists(map.get(LoaderEventType.CachedDataFound)); - md.heading(3, 'cached data missed'); - printLists(map.get(LoaderEventType.CachedDataMissed)); - md.heading(3, 'cached data rejected'); - printLists(map.get(LoaderEventType.CachedDataRejected)); - md.heading(3, 'cached data created (lazy, might need refreshes)'); - printLists(map.get(LoaderEventType.CachedDataCreated)); } } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 75d7399be8..2b253a63b9 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Delayer } from 'vs/base/common/async'; import * as DOM from 'vs/base/browser/dom'; import { OS } from 'vs/base/common/platform'; -import { dispose, Disposable, toDisposable, IDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable, toDisposable, IDisposable } from 'vs/base/common/lifecycle'; import { CheckboxActionViewItem } from 'vs/base/browser/ui/checkbox/checkbox'; import { HighlightedLabel } from 'vs/base/browser/ui/highlightedlabel/highlightedLabel'; import { KeybindingLabel } from 'vs/base/browser/ui/keybindingLabel/keybindingLabel'; @@ -804,7 +804,7 @@ class KeybindingItemRenderer implements IListRenderer element); this.keybindingsEditor.layoutColumns(elements); @@ -814,7 +814,7 @@ class KeybindingItemRenderer implements IListRenderer dispose(disposables)) }; } diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts index 4324c3b83b..1847e7378a 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditorContribution.ts @@ -23,13 +23,11 @@ import { parseTree, Node } from 'vs/base/common/json'; import { ScanCodeBinding } from 'vs/base/common/scanCode'; import { EditorContextKeys } from 'vs/editor/common/editorContextKeys'; import { WindowsNativeResolvedKeybinding } from 'vs/workbench/services/keybinding/common/windowsKeyboardMapper'; -import { themeColorFromId, ThemeColor, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; +import { themeColorFromId, ThemeColor } from 'vs/platform/theme/common/themeService'; import { overviewRulerInfo, overviewRulerError } from 'vs/editor/common/view/editorColorRegistry'; import { IModelDeltaDecoration, ITextModel, TrackedRangeStickiness, OverviewRulerLane } from 'vs/editor/common/model'; import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { KeybindingParser } from 'vs/base/common/keybindingParser'; -import Severity from 'vs/base/common/severity'; -import { SeverityIcon } from 'vs/platform/severityIcon/common/severityIcon'; const NLS_LAUNCH_MESSAGE = nls.localize('defineKeybinding.start', "Define Keybinding"); const NLS_KB_LAYOUT_ERROR_MESSAGE = nls.localize('defineKeybinding.kbLayoutErrorMessage', "You won't be able to produce this key combination under your current keyboard layout."); @@ -402,8 +400,3 @@ function isInterestingEditorModel(editor: ICodeEditor): boolean { registerEditorContribution(DefineKeybindingController); registerEditorCommand(new DefineKeybindingCommand()); - -registerThemingParticipant((theme, collector) => { - collector.addRule(`.monaco-editor .inlineKeybindingInfo:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Info, theme)}") -0.1em -0.2em no-repeat; }`); - collector.addRule(`.monaco-editor .inlineKeybindingError:before { background: url("data:image/svg+xml,${SeverityIcon.getSVGData(Severity.Error, theme)}") -0.1em -0.2em no-repeat; }`); -}); \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/info.svg b/src/vs/workbench/contrib/preferences/browser/media/info.svg new file mode 100644 index 0000000000..6578b81ea3 --- /dev/null +++ b/src/vs/workbench/contrib/preferences/browser/media/info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/media/keybindings.css b/src/vs/workbench/contrib/preferences/browser/media/keybindings.css index 935d90fa26..c523a5920f 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/keybindings.css +++ b/src/vs/workbench/contrib/preferences/browser/media/keybindings.css @@ -47,6 +47,7 @@ display:inline-block; height:0.8em; width:1em; + background: url(info.svg) 0px -0.1em no-repeat; background-size: 0.9em; } @@ -56,6 +57,7 @@ display:inline-block; height:0.8em; width:1em; + background: url(status-error.svg) 0px -0.1em no-repeat; background-size: 1em; } diff --git a/src/vs/workbench/contrib/preferences/browser/media/preferences.css b/src/vs/workbench/contrib/preferences/browser/media/preferences.css index 3c36b41cb2..9e5f46e3b1 100644 --- a/src/vs/workbench/contrib/preferences/browser/media/preferences.css +++ b/src/vs/workbench/contrib/preferences/browser/media/preferences.css @@ -236,6 +236,15 @@ background: url('edit_inverse.svg') center center no-repeat; } +.monaco-editor .unsupportedWorkbenhSettingInfo:before { + content:" "; + display:inline-block; + height:1em; + width:1em; + background: url(info.svg) 50% 50% no-repeat; + background-size: 0.9em; +} + .monaco-editor .dim-configuration { color: #b1b1b1; } diff --git a/src/vs/workbench/contrib/preferences/browser/media/status-error.svg b/src/vs/workbench/contrib/preferences/browser/media/status-error.svg new file mode 100644 index 0000000000..a1ddb39fed --- /dev/null +++ b/src/vs/workbench/contrib/preferences/browser/media/status-error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts b/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts index e428e6df32..c3f19e77a3 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesActions.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { Action } from 'vs/base/common/actions'; -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { getIconClasses } from 'vs/editor/common/services/getIconClasses'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -164,7 +164,7 @@ export class OpenWorkspaceSettingsAction extends Action { static readonly ID = 'workbench.action.openWorkspaceSettings'; static readonly LABEL = nls.localize('openWorkspaceSettings', "Open Workspace Settings"); - private readonly disposables = new DisposableStore(); + private disposables: IDisposable[] = []; constructor( id: string, @@ -174,7 +174,7 @@ export class OpenWorkspaceSettingsAction extends Action { ) { super(id, label); this.update(); - this.disposables.add(this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this)); + this.workspaceContextService.onDidChangeWorkbenchState(() => this.update(), this, this.disposables); } private update(): void { @@ -186,7 +186,7 @@ export class OpenWorkspaceSettingsAction extends Action { } dispose(): void { - this.disposables.dispose(); + this.disposables = dispose(this.disposables); super.dispose(); } } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index f12f2fd0d4..b062bfec4f 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -31,7 +31,7 @@ import { ConfigurationTarget } from 'vs/platform/configuration/common/configurat import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILogService } from 'vs/platform/log/common/log'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; import { Registry } from 'vs/platform/registry/common/platform'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -84,7 +84,7 @@ export class PreferencesEditor extends BaseEditor { readonly minimumHeight = 260; - private _onDidCreateWidget = this._register(new Emitter<{ width: number; height: number; } | undefined>()); + private _onDidCreateWidget = new Emitter<{ width: number; height: number; } | undefined>(); readonly onDidSizeConstraintsChange: Event<{ width: number; height: number; } | undefined> = this._onDidCreateWidget.event; constructor( @@ -94,7 +94,7 @@ export class PreferencesEditor extends BaseEditor { @IContextKeyService private readonly contextKeyService: IContextKeyService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IThemeService themeService: IThemeService, - @ILocalProgressService private readonly progressService: ILocalProgressService, + @IProgressService private readonly progressService: IProgressService, @IStorageService storageService: IStorageService ) { super(PreferencesEditor.ID, telemetryService, themeService, storageService); @@ -330,6 +330,11 @@ export class PreferencesEditor extends BaseEditor { this._lastReportedFilter = filter; } } + + dispose(): void { + this._onDidCreateWidget.dispose(); + super.dispose(); + } } class SettingsNavigator extends ArrayNavigator { @@ -769,10 +774,10 @@ class SideBySidePreferencesWidget extends Widget { private settingsTargetsWidget: SettingsTargetsWidget; - private readonly _onFocus = this._register(new Emitter()); + private readonly _onFocus = new Emitter(); readonly onFocus: Event = this._onFocus.event; - private readonly _onDidSettingsTargetChange = this._register(new Emitter()); + private readonly _onDidSettingsTargetChange = new Emitter(); readonly onDidSettingsTargetChange: Event = this._onDidSettingsTargetChange.event; private splitview: SplitView; diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index 5982c1c5d0..98a8d5505e 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -56,13 +56,13 @@ export class UserSettingsRenderer extends Disposable implements IPreferencesRend private modelChangeDelayer: Delayer = new Delayer(200); private associatedPreferencesModel: IPreferencesEditorModel; - private readonly _onFocusPreference = this._register(new Emitter()); + private readonly _onFocusPreference = new Emitter(); readonly onFocusPreference: Event = this._onFocusPreference.event; - private readonly _onClearFocusPreference = this._register(new Emitter()); + private readonly _onClearFocusPreference = new Emitter(); readonly onClearFocusPreference: Event = this._onClearFocusPreference.event; - private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>()); + private readonly _onUpdatePreference: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>(); readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event; private filterResult: IFilterResult | undefined; @@ -233,13 +233,13 @@ export class DefaultSettingsRenderer extends Disposable implements IPreferencesR private bracesHidingRenderer: BracesHidingRenderer; private filterResult: IFilterResult | undefined; - private readonly _onUpdatePreference = this._register(new Emitter<{ key: string, value: any, source: IIndexedSetting }>()); + private readonly _onUpdatePreference: Emitter<{ key: string, value: any, source: IIndexedSetting }> = new Emitter<{ key: string, value: any, source: IIndexedSetting }>(); readonly onUpdatePreference: Event<{ key: string, value: any, source: IIndexedSetting }> = this._onUpdatePreference.event; - private readonly _onFocusPreference = this._register(new Emitter()); + private readonly _onFocusPreference = new Emitter(); readonly onFocusPreference: Event = this._onFocusPreference.event; - private readonly _onClearFocusPreference = this._register(new Emitter()); + private readonly _onClearFocusPreference = new Emitter(); readonly onClearFocusPreference: Event = this._onClearFocusPreference.event; constructor(protected editor: ICodeEditor, readonly preferencesModel: DefaultSettingsEditorModel, @@ -436,13 +436,13 @@ class DefaultSettingsHeaderRenderer extends Disposable { export class SettingsGroupTitleRenderer extends Disposable implements HiddenAreasProvider { - private readonly _onHiddenAreasChanged = this._register(new Emitter()); + private readonly _onHiddenAreasChanged = new Emitter(); get onHiddenAreasChanged(): Event { return this._onHiddenAreasChanged.event; } private settingsGroups: ISettingsGroup[]; private hiddenGroups: ISettingsGroup[] = []; private settingsGroupTitleWidgets: SettingsGroupTitleWidget[]; - private renderDisposables: IDisposable[] = []; + private disposables: IDisposable[] = []; constructor(private editor: ICodeEditor, @IInstantiationService private readonly instantiationService: IInstantiationService @@ -474,8 +474,8 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea const settingsGroupTitleWidget = this.instantiationService.createInstance(SettingsGroupTitleWidget, this.editor, group); settingsGroupTitleWidget.render(); this.settingsGroupTitleWidgets.push(settingsGroupTitleWidget); - this.renderDisposables.push(settingsGroupTitleWidget); - this.renderDisposables.push(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup))); + this.disposables.push(settingsGroupTitleWidget); + this.disposables.push(settingsGroupTitleWidget.onToggled(collapsed => this.onToggled(collapsed, settingsGroupTitleWidget.settingsGroup))); } this.settingsGroupTitleWidgets.reverse(); } @@ -515,7 +515,7 @@ export class SettingsGroupTitleRenderer extends Disposable implements HiddenArea private disposeWidgets() { this.hiddenGroups = []; - this.renderDisposables = dispose(this.renderDisposables); + this.disposables = dispose(this.disposables); } dispose() { diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts deleted file mode 100644 index bc087bc134..0000000000 --- a/src/vs/workbench/contrib/preferences/browser/preferencesSearch.ts +++ /dev/null @@ -1,219 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ISettingsEditorModel, ISetting, ISettingsGroup, ISearchResult, IGroupFilter } from 'vs/workbench/services/preferences/common/preferences'; -import { IRange } from 'vs/editor/common/core/range'; -import { distinct } from 'vs/base/common/arrays'; -import * as strings from 'vs/base/common/strings'; -import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; -import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { Disposable } from 'vs/base/common/lifecycle'; -import { IPreferencesSearchService, ISearchProvider } from 'vs/workbench/contrib/preferences/common/preferences'; -import { CancellationToken } from 'vs/base/common/cancellation'; - -export interface IEndpointDetails { - urlBase?: string; - key?: string; -} - -export class PreferencesSearchService extends Disposable implements IPreferencesSearchService { - _serviceBrand: any; - - constructor( - @IInstantiationService protected readonly instantiationService: IInstantiationService, - ) { - super(); - } - - getRemoteSearchProvider(filter: string, newExtensionsOnly = false): ISearchProvider | undefined { - return undefined; - } - - getLocalSearchProvider(filter: string): LocalSearchProvider { - return this.instantiationService.createInstance(LocalSearchProvider, filter); - } -} - -export class LocalSearchProvider implements ISearchProvider { - static readonly EXACT_MATCH_SCORE = 10000; - static readonly START_SCORE = 1000; - - constructor(private _filter: string) { - // Remove " and : which are likely to be copypasted as part of a setting name. - // Leave other special characters which the user might want to search for. - this._filter = this._filter - .replace(/[":]/g, ' ') - .replace(/ /g, ' ') - .trim(); - } - - searchModel(preferencesModel: ISettingsEditorModel, token?: CancellationToken): Promise { - if (!this._filter) { - return Promise.resolve(null); - } - - let orderedScore = LocalSearchProvider.START_SCORE; // Sort is not stable - const settingMatcher = (setting: ISetting) => { - const matches = new SettingMatches(this._filter, setting, true, true, (filter, setting) => preferencesModel.findValueMatches(filter, setting)).matches; - const score = this._filter === setting.key ? - LocalSearchProvider.EXACT_MATCH_SCORE : - orderedScore--; - - return matches && matches.length ? - { - matches, - score - } : - null; - }; - - const filterMatches = preferencesModel.filterSettings(this._filter, this.getGroupFilter(this._filter), settingMatcher); - if (filterMatches[0] && filterMatches[0].score === LocalSearchProvider.EXACT_MATCH_SCORE) { - return Promise.resolve({ - filterMatches: filterMatches.slice(0, 1), - exactMatch: true - }); - } else { - return Promise.resolve({ - filterMatches - }); - } - } - - private getGroupFilter(filter: string): IGroupFilter { - const regex = strings.createRegExp(filter, false, { global: true }); - return (group: ISettingsGroup) => { - return regex.test(group.title); - }; - } -} - -export class SettingMatches { - - private readonly descriptionMatchingWords: Map = new Map(); - private readonly keyMatchingWords: Map = new Map(); - private readonly valueMatchingWords: Map = new Map(); - - readonly matches: IRange[]; - - constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { - this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); - } - - private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const result = this._doFindMatchesInSetting(searchString, setting); - if (setting.overrides && setting.overrides.length) { - for (const subSetting of setting.overrides) { - const subSettingMatches = new SettingMatches(searchString, subSetting, this.requireFullQueryMatch, this.searchDescription, this.valuesMatcher); - const words = searchString.split(' '); - const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); - const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); - result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); - result.push(...subSettingMatches.matches); - } - } - return result; - } - - private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { - const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); - const schema: IJSONSchema = registry[setting.key]; - - const words = searchString.split(' '); - const settingKeyAsWords: string = setting.key.split('.').join(' '); - - for (const word of words) { - if (this.searchDescription) { - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); - if (descriptionMatches) { - this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - } - } - - const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); - if (keyMatches) { - this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); - } - - const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; - if (valueMatches) { - this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); - } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { - this.valueMatchingWords.set(word, []); - } - } - - const descriptionRanges: IRange[] = []; - if (this.searchDescription) { - for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { - const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; - descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); - } - if (descriptionRanges.length === 0) { - descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); - } - } - - const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); - const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); - - let valueRanges: IRange[] = []; - if (setting.value && typeof setting.value === 'string') { - const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); - valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); - } else { - valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : []; - } - - return [...descriptionRanges, ...keyRanges, ...valueRanges]; - } - - private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { - const result: IRange[] = []; - for (const word of words) { - const ranges = from.get(word); - if (ranges) { - result.push(...ranges); - } else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) { - return []; - } - } - return result; - } - - private toKeyRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn + match.start, - endLineNumber: setting.keyRange.startLineNumber, - endColumn: setting.keyRange.startColumn + match.end - }; - } - - private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { - return { - startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, - startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, - endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, - endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end - }; - } - - private toValueRange(setting: ISetting, match: IMatch): IRange { - return { - startLineNumber: setting.valueRange.startLineNumber, - startColumn: setting.valueRange.startColumn + match.start + 1, - endLineNumber: setting.valueRange.startLineNumber, - endColumn: setting.valueRange.startColumn + match.end + 1 - }; - } -} \ No newline at end of file diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts index e336c159b3..87b297db14 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesWidgets.ts @@ -484,7 +484,7 @@ export class SettingsTargetsWidget extends Widget { private _settingsTarget: SettingsTarget; - private readonly _onDidTargetChange = this._register(new Emitter()); + private readonly _onDidTargetChange = new Emitter(); readonly onDidTargetChange: Event = this._onDidTargetChange.event; constructor( @@ -517,7 +517,7 @@ export class SettingsTargetsWidget extends Widget { const remoteAuthority = this.environmentService.configuration.remoteAuthority; const hostLabel = remoteAuthority && this.labelService.getHostLabel(REMOTE_HOST_SCHEME, remoteAuthority); const remoteSettingsLabel = localize('userSettingsRemote', "Remote") + - (hostLabel ? ` [${hostLabel}]` : ''); + (hostLabel ? ` (${hostLabel})` : ''); this.userRemoteSettings = new Action('userSettingsRemote', remoteSettingsLabel, '.settings-tab', true, () => this.updateTarget(ConfigurationTarget.USER_REMOTE)); this.userRemoteSettings.tooltip = this.userRemoteSettings.label; @@ -751,7 +751,7 @@ export class EditPreferenceWidget extends Disposable { private _editPreferenceDecoration: string[]; - private readonly _onClick = this._register(new Emitter()); + private readonly _onClick = new Emitter(); get onClick(): Event { return this._onClick.event; } constructor(private editor: ICodeEditor diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts index 04aa9020d6..b75e240239 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTree.ts @@ -25,7 +25,7 @@ import { Color, RGBA } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Emitter, Event } from 'vs/base/common/event'; import { KeyCode } from 'vs/base/common/keyCodes'; -import { dispose, IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { ISpliceable } from 'vs/base/common/sequence'; import { escapeRegExpCharacters, startsWith } from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; @@ -45,7 +45,6 @@ import { ISettingsEditorViewState, settingKeyToDisplayFormat, SettingsTreeElemen import { ExcludeSettingWidget, IExcludeChangeEvent, IExcludeDataItem, settingsHeaderForeground, settingsNumberInputBackground, settingsNumberInputBorder, settingsNumberInputForeground, settingsSelectBackground, settingsSelectBorder, settingsSelectForeground, settingsSelectListBorder, settingsTextInputBackground, settingsTextInputBorder, settingsTextInputForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU } from 'vs/workbench/contrib/preferences/common/preferences'; import { ISetting, ISettingsGroup, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; const $ = DOM.$; @@ -250,7 +249,7 @@ export interface ISettingOverrideClickEvent { targetKey: string; } -export abstract class AbstractSettingRenderer extends Disposable implements ITreeRenderer { +export abstract class AbstractSettingRenderer implements ITreeRenderer { /** To override */ abstract get templateId(): string; @@ -262,19 +261,19 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre static readonly SETTING_KEY_ATTR = 'data-key'; static readonly SETTING_ID_ATTR = 'data-id'; - private readonly _onDidClickOverrideElement = this._register(new Emitter()); + private readonly _onDidClickOverrideElement = new Emitter(); readonly onDidClickOverrideElement: Event = this._onDidClickOverrideElement.event; - protected readonly _onDidChangeSetting = this._register(new Emitter()); + protected readonly _onDidChangeSetting = new Emitter(); readonly onDidChangeSetting: Event = this._onDidChangeSetting.event; - protected readonly _onDidOpenSettings = this._register(new Emitter()); + protected readonly _onDidOpenSettings = new Emitter(); readonly onDidOpenSettings: Event = this._onDidOpenSettings.event; - private readonly _onDidClickSettingLink = this._register(new Emitter()); + private readonly _onDidClickSettingLink = new Emitter(); readonly onDidClickSettingLink: Event = this._onDidClickSettingLink.event; - private readonly _onDidFocusSetting = this._register(new Emitter()); + private readonly _onDidFocusSetting = new Emitter(); readonly onDidFocusSetting: Event = this._onDidFocusSetting.event; // Put common injections back here @@ -288,7 +287,6 @@ export abstract class AbstractSettingRenderer extends Disposable implements ITre @IContextMenuService protected readonly _contextMenuService: IContextMenuService, @IKeybindingService protected readonly _keybindingService: IKeybindingService, ) { - super(); } renderTemplate(container: HTMLElement): any { @@ -941,11 +939,11 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre const deprecationWarningElement = DOM.append(container, $('.setting-item-deprecation-message')); - const toDispose = new DisposableStore(); + const toDispose: IDisposable[] = []; const checkbox = new Checkbox({ actionClassName: 'setting-value-checkbox', isChecked: true, title: '', inputActiveOptionBorder: undefined }); controlElement.appendChild(checkbox.domNode); - toDispose.add(checkbox); - toDispose.add(checkbox.onChange(() => { + toDispose.push(checkbox); + toDispose.push(checkbox.onChange(() => { if (template.onChange) { template.onChange(checkbox.checked); } @@ -953,7 +951,7 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre // Need to listen for mouse clicks on description and toggle checkbox - use target ID for safety // Also have to ignore embedded links - too buried to stop propagation - toDispose.add(DOM.addDisposableListener(descriptionElement, DOM.EventType.MOUSE_DOWN, (e) => { + toDispose.push(DOM.addDisposableListener(descriptionElement, DOM.EventType.MOUSE_DOWN, (e) => { const targetElement = e.target; const targetId = descriptionElement.getAttribute('checkbox_label_target_id'); @@ -970,10 +968,10 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre checkbox.domNode.classList.add(AbstractSettingRenderer.CONTROL_CLASS); const toolbarContainer = DOM.append(container, $('.setting-toolbar-container')); const toolbar = this.renderSettingToolbar(toolbarContainer); - toDispose.add(toolbar); + toDispose.push(toolbar); const template: ISettingBoolItemTemplate = { - toDispose: [toDispose], + toDispose, containerElement: container, categoryElement, @@ -989,16 +987,16 @@ export class SettingBoolRenderer extends AbstractSettingRenderer implements ITre this.addSettingElementFocusHandler(template); // Prevent clicks from being handled by list - toDispose.add(DOM.addDisposableListener(controlElement, 'mousedown', (e: IMouseEvent) => e.stopPropagation())); + toDispose.push(DOM.addDisposableListener(controlElement, 'mousedown', (e: IMouseEvent) => e.stopPropagation())); - toDispose.add(DOM.addStandardDisposableListener(controlElement, 'keydown', (e: StandardKeyboardEvent) => { + toDispose.push(DOM.addStandardDisposableListener(controlElement, 'keydown', (e: StandardKeyboardEvent) => { if (e.keyCode === KeyCode.Escape) { e.browserEvent.stopPropagation(); } })); - toDispose.add(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_ENTER, e => container.classList.add('mouseover'))); - toDispose.add(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover'))); + toDispose.push(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_ENTER, e => container.classList.add('mouseover'))); + toDispose.push(DOM.addDisposableListener(titleElement, DOM.EventType.MOUSE_LEAVE, e => container.classList.remove('mouseover'))); return template; } @@ -1165,7 +1163,6 @@ function escapeInvisibleChars(enumValue: string): string { export class SettingsTreeFilter implements ITreeFilter { constructor( private viewState: ISettingsEditorViewState, - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, ) { } filter(element: SettingsTreeElement, parentVisibility: TreeVisibility): TreeFilterResult { @@ -1178,8 +1175,7 @@ export class SettingsTreeFilter implements ITreeFilter { // Non-user scope selected if (element instanceof SettingsTreeSettingElement && this.viewState.settingsTarget !== ConfigurationTarget.USER_LOCAL) { - const isRemote = !!this.environmentService.configuration.remoteAuthority; - if (!element.matchesScope(this.viewState.settingsTarget, isRemote)) { + if (!element.matchesScope(this.viewState.settingsTarget)) { return false; } } @@ -1307,8 +1303,7 @@ export class SettingsTree extends ObjectTree { container: HTMLElement, viewState: ISettingsEditorViewState, renderers: ITreeRenderer[], - @IThemeService themeService: IThemeService, - @IInstantiationService instantiationService: IInstantiationService, + @IThemeService themeService: IThemeService ) { const treeClass = 'settings-editor-tree'; @@ -1325,7 +1320,7 @@ export class SettingsTree extends ObjectTree { } }, styleController: new DefaultStyleController(DOM.createStyleSheet(container), treeClass), - filter: instantiationService.createInstance(SettingsTreeFilter, viewState) + filter: new SettingsTreeFilter(viewState) }); this.disposables = []; diff --git a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts index 1b2f011708..08d0d16094 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsTreeModels.ts @@ -14,7 +14,6 @@ import { SettingsTarget } from 'vs/workbench/contrib/preferences/browser/prefere import { ITOCEntry, knownAcronyms, knownTermMappings } from 'vs/workbench/contrib/preferences/browser/settingsLayout'; import { MODIFIED_SETTING_TAG } from 'vs/workbench/contrib/preferences/common/preferences'; import { IExtensionSetting, ISearchResult, ISetting, SettingValueType } from 'vs/workbench/services/preferences/common/preferences'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; export const ONLINE_SERVICES_SETTING_TAG = 'usesOnlineServices'; @@ -222,7 +221,7 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { } } - matchesScope(scope: SettingsTarget, isRemote: boolean): boolean { + matchesScope(scope: SettingsTarget): boolean { const configTarget = URI.isUri(scope) ? ConfigurationTarget.WORKSPACE_FOLDER : scope; if (configTarget === ConfigurationTarget.WORKSPACE_FOLDER) { @@ -237,10 +236,6 @@ export class SettingsTreeSettingElement extends SettingsTreeElement { return this.setting.scope === ConfigurationScope.MACHINE || this.setting.scope === ConfigurationScope.WINDOW || this.setting.scope === ConfigurationScope.RESOURCE; } - if (configTarget === ConfigurationTarget.USER_LOCAL && isRemote) { - return this.setting.scope !== ConfigurationScope.MACHINE; - } - return true; } @@ -484,8 +479,7 @@ export class SearchResultModel extends SettingsTreeModel { constructor( viewState: ISettingsEditorViewState, - @IConfigurationService configurationService: IConfigurationService, - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, + @IConfigurationService configurationService: IConfigurationService ) { super(viewState, configurationService); this.update({ id: 'searchResultModel', label: '' }); @@ -543,9 +537,8 @@ export class SearchResultModel extends SettingsTreeModel { }); // Save time, filter children in the search model instead of relying on the tree filter, which still requires heights to be calculated. - const isRemote = !!this.environmentService.configuration.remoteAuthority; this.root.children = this.root.children - .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAnyExtension(this._viewState.extensionFilters)); + .filter(child => child instanceof SettingsTreeSettingElement && child.matchesAllTags(this._viewState.tagFilters) && child.matchesScope(this._viewState.settingsTarget) && child.matchesAnyExtension(this._viewState.extensionFilters)); if (this.newExtensionSearchResults && this.newExtensionSearchResults.filterMatches.length) { const newExtElement = new SettingsTreeNewExtensionsElement(); diff --git a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts index 57708110af..e0b861c524 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts +++ b/src/vs/workbench/contrib/preferences/browser/settingsWidgets.ts @@ -203,7 +203,7 @@ export class ExcludeSettingWidget extends Disposable { private model = new ExcludeSettingListModel(); - private readonly _onDidChangeExclude = this._register(new Emitter()); + private readonly _onDidChangeExclude = new Emitter(); readonly onDidChangeExclude: Event = this._onDidChangeExclude.event; get domNode(): HTMLElement { diff --git a/src/vs/workbench/contrib/preferences/browser/tocTree.ts b/src/vs/workbench/contrib/preferences/browser/tocTree.ts index 891b6a4108..000197065a 100644 --- a/src/vs/workbench/contrib/preferences/browser/tocTree.ts +++ b/src/vs/workbench/contrib/preferences/browser/tocTree.ts @@ -17,7 +17,6 @@ import { SettingsTreeFilter } from 'vs/workbench/contrib/preferences/browser/set import { ISettingsEditorViewState, SearchResultModel, SettingsTreeElement, SettingsTreeGroupElement, SettingsTreeSettingElement } from 'vs/workbench/contrib/preferences/browser/settingsTreeModels'; import { settingsHeaderForeground } from 'vs/workbench/contrib/preferences/browser/settingsWidgets'; import { localize } from 'vs/nls'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; const $ = DOM.$; @@ -26,10 +25,7 @@ export class TOCTreeModel { private _currentSearchModel: SearchResultModel | null; private _settingsTreeRoot: SettingsTreeGroupElement; - constructor( - private _viewState: ISettingsEditorViewState, - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService - ) { + constructor(private _viewState: ISettingsEditorViewState) { } get settingsTreeRoot(): SettingsTreeGroupElement { @@ -85,8 +81,7 @@ export class TOCTreeModel { } // Check everything that the SettingsFilter checks except whether it's filtered by a category - const isRemote = !!this.environmentService.configuration.remoteAuthority; - return child.matchesScope(this._viewState.settingsTarget, isRemote) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters); + return child.matchesScope(this._viewState.settingsTarget) && child.matchesAllTags(this._viewState.tagFilters) && child.matchesAnyExtension(this._viewState.extensionFilters); }).length; } } diff --git a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts index 2a6686acbd..5453db8b2f 100644 --- a/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts +++ b/src/vs/workbench/contrib/preferences/common/preferencesContribution.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { isLinux } from 'vs/base/common/platform'; import { isEqual } from 'vs/base/common/resources'; import { endsWith } from 'vs/base/common/strings'; @@ -79,7 +79,7 @@ export class PreferencesContribution implements IWorkbenchContribution { } // Global User Settings File - if (isEqual(resource, this.environmentService.settingsResource, !isLinux)) { + if (isEqual(resource, URI.file(this.environmentService.appSettingsPath), !isLinux)) { return { override: this.preferencesService.openGlobalSettings(true, options, group) }; } @@ -129,14 +129,14 @@ export class PreferencesContribution implements IWorkbenchContribution { const modelContent = JSON.stringify(schema); const languageSelection = this.modeService.create('jsonc'); const model = this.modelService.createModel(modelContent, languageSelection, uri); - const disposables = new DisposableStore(); - disposables.add(schemaRegistry.onDidChangeSchema(schemaUri => { + const disposables: IDisposable[] = []; + disposables.push(schemaRegistry.onDidChangeSchema(schemaUri => { if (schemaUri === uri.toString()) { schema = schemaRegistry.getSchemaContributions().schemas[uri.toString()]; model.setValue(JSON.stringify(schema)); } })); - disposables.add(model.onWillDispose(() => disposables.dispose())); + disposables.push(model.onWillDispose(() => dispose(disposables))); return model; } diff --git a/src/vs/workbench/contrib/preferences/browser/media/check-inverse.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/check-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/check-inverse.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/check-inverse.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/check.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/check.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/check.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/check.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/configure-inverse.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/configure-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/configure-inverse.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/configure-inverse.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/configure.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/configure.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/configure.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/configure.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/edit-json.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/edit-json.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/preferences-editor.svg b/src/vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/preferences-editor.svg rename to src/vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg diff --git a/src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css b/src/vs/workbench/contrib/preferences/electron-browser/media/settingsEditor2.css similarity index 100% rename from src/vs/workbench/contrib/preferences/browser/media/settingsEditor2.css rename to src/vs/workbench/contrib/preferences/electron-browser/media/settingsEditor2.css diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts similarity index 93% rename from src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts rename to src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts index 39e4e98608..36dbbbd540 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferences.contribution.ts @@ -16,6 +16,7 @@ import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { WorkbenchStateContext, RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -29,9 +30,10 @@ import { ResourceContextKey } from 'vs/workbench/common/resources'; import { KeybindingsEditor } from 'vs/workbench/contrib/preferences/browser/keybindingsEditor'; import { ConfigureLanguageBasedSettingsAction, OpenDefaultKeybindingsFileAction, OpenFolderSettingsAction, OpenGlobalKeybindingsAction, OpenGlobalKeybindingsFileAction, OpenGlobalSettingsAction, OpenRawDefaultSettingsAction, OpenSettings2Action, OpenSettingsJsonAction, OpenWorkspaceSettingsAction, OPEN_FOLDER_SETTINGS_COMMAND, OPEN_FOLDER_SETTINGS_LABEL, OpenRemoteSettingsAction } from 'vs/workbench/contrib/preferences/browser/preferencesActions'; import { PreferencesEditor } from 'vs/workbench/contrib/preferences/browser/preferencesEditor'; -import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences'; +import { CONTEXT_KEYBINDINGS_EDITOR, CONTEXT_KEYBINDINGS_SEARCH_FOCUS, CONTEXT_KEYBINDING_FOCUS, CONTEXT_SETTINGS_EDITOR, CONTEXT_SETTINGS_JSON_EDITOR, CONTEXT_SETTINGS_SEARCH_FOCUS, CONTEXT_TOC_ROW_FOCUS, IKeybindingsEditor, IPreferencesSearchService, KEYBINDINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, KEYBINDINGS_EDITOR_COMMAND_COPY, KEYBINDINGS_EDITOR_COMMAND_COPY_COMMAND, KEYBINDINGS_EDITOR_COMMAND_DEFINE, KEYBINDINGS_EDITOR_COMMAND_FOCUS_KEYBINDINGS, KEYBINDINGS_EDITOR_COMMAND_RECORD_SEARCH_KEYS, KEYBINDINGS_EDITOR_COMMAND_REMOVE, KEYBINDINGS_EDITOR_COMMAND_RESET, KEYBINDINGS_EDITOR_COMMAND_SEARCH, KEYBINDINGS_EDITOR_COMMAND_SHOW_SIMILAR, KEYBINDINGS_EDITOR_COMMAND_SORTBY_PRECEDENCE, KEYBINDINGS_EDITOR_SHOW_DEFAULT_KEYBINDINGS, KEYBINDINGS_EDITOR_SHOW_USER_KEYBINDINGS, MODIFIED_SETTING_TAG, SETTINGS_EDITOR_COMMAND_CLEAR_SEARCH_RESULTS, SETTINGS_EDITOR_COMMAND_EDIT_FOCUSED_SETTING, SETTINGS_EDITOR_COMMAND_FILTER_MODIFIED, SETTINGS_EDITOR_COMMAND_FILTER_ONLINE, SETTINGS_EDITOR_COMMAND_FOCUS_FILE, SETTINGS_EDITOR_COMMAND_FOCUS_NEXT_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_PREVIOUS_SETTING, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_FROM_SEARCH, SETTINGS_EDITOR_COMMAND_FOCUS_SETTINGS_LIST, SETTINGS_EDITOR_COMMAND_SEARCH, SETTINGS_EDITOR_COMMAND_SHOW_CONTEXT_MENU, SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, SETTINGS_COMMAND_OPEN_SETTINGS, KEYBINDINGS_EDITOR_COMMAND_DEFINE_WHEN } from 'vs/workbench/contrib/preferences/common/preferences'; import { PreferencesContribution } from 'vs/workbench/contrib/preferences/common/preferencesContribution'; -import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/browser/settingsEditor2'; +import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch'; +import { SettingsEditor2 } from 'vs/workbench/contrib/preferences/electron-browser/settingsEditor2'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IPreferencesService } from 'vs/workbench/services/preferences/common/preferences'; import { DefaultPreferencesEditorInput, KeybindingsEditorInput, PreferencesEditorInput, SettingsEditor2Input } from 'vs/workbench/services/preferences/common/preferencesEditorInput'; @@ -40,6 +42,8 @@ import { ILabelService } from 'vs/platform/label/common/label'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; +registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); + Registry.as(EditorExtensions.Editors).registerEditor( new EditorDescriptor( PreferencesEditor, @@ -381,8 +385,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: OpenGlobalKeybindingsAction.ID, title: OpenGlobalKeybindingsAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`)) } }, when: ResourceContextKey.Resource.isEqualTo(URI.file(environmentService.appKeybindingsPath).toString()), @@ -397,11 +401,11 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`)) } }, - when: ResourceContextKey.Resource.isEqualTo(environmentService.settingsResource.toString()), + when: ResourceContextKey.Resource.isEqualTo(URI.file(environmentService.appSettingsPath).toString()), group: 'navigation', order: 1 }); @@ -438,8 +442,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`)) } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.workspaceSettingsResource!.toString()), WorkbenchStateContext.isEqualTo('workspace')), @@ -466,8 +470,8 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon id: commandId, title: OpenSettings2Action.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/preferences-editor-inverse.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/preferences-editor-inverse.svg`)) } }, when: ContextKeyExpr.and(ResourceContextKey.Resource.isEqualTo(this.preferencesService.getFolderSettingsResource(folder.uri)!.toString())), @@ -533,8 +537,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: OpenGlobalKeybindingsFileAction.ID, title: OpenGlobalKeybindingsFileAction.LABEL, iconLocation: { - light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json.svg`)), - dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg`)) + light: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg`)), + dark: URI.parse(require.toUrl(`vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg`)) } }, when: ContextKeyExpr.and(CONTEXT_KEYBINDINGS_EDITOR), @@ -771,8 +775,8 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { id: SETTINGS_EDITOR_COMMAND_SWITCH_TO_JSON, title: nls.localize('openSettingsJson', "Open Settings (JSON)"), iconLocation: { - dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json-inverse.svg')), - light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/browser/media/edit-json.svg')) + dark: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json-inverse.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/preferences/electron-browser/media/edit-json.svg')) } }, group: 'navigation', diff --git a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts b/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts index 625dce6d83..69accb99c9 100644 --- a/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/preferencesSearch.ts @@ -4,12 +4,18 @@ *--------------------------------------------------------------------------------------------*/ import { ISettingsEditorModel, ISetting, ISettingsGroup, IFilterMetadata, ISearchResult, IGroupFilter, ISettingMatcher, IScoredResults, ISettingMatch, IRemoteSetting, IExtensionSetting } from 'vs/workbench/services/preferences/common/preferences'; -import { top } from 'vs/base/common/arrays'; +import { IRange } from 'vs/editor/common/core/range'; +import { distinct, top } from 'vs/base/common/arrays'; import * as strings from 'vs/base/common/strings'; +import { IJSONSchema } from 'vs/base/common/jsonSchema'; +import { Registry } from 'vs/platform/registry/common/platform'; +import { IConfigurationRegistry, Extensions } from 'vs/platform/configuration/common/configurationRegistry'; +import { IMatch, or, matchesContiguousSubString, matchesPrefix, matchesCamelCase, matchesWords } from 'vs/base/common/filters'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IRequestService } from 'vs/platform/request/node/request'; import { asJson } from 'vs/base/node/request'; +import { Disposable } from 'vs/base/common/lifecycle'; import { IExtensionManagementService, ILocalExtension, IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { ILogService } from 'vs/platform/log/common/log'; import { IPreferencesSearchService, ISearchProvider, IWorkbenchSettingsConfiguration } from 'vs/workbench/contrib/preferences/common/preferences'; @@ -18,26 +24,25 @@ import { canceled } from 'vs/base/common/errors'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { nullRange } from 'vs/workbench/services/preferences/common/preferencesModels'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { PreferencesSearchService as LocalPreferencesSearchService, SettingMatches } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; export interface IEndpointDetails { urlBase?: string; key?: string; } -export class PreferencesSearchService extends LocalPreferencesSearchService implements IPreferencesSearchService { +export class PreferencesSearchService extends Disposable implements IPreferencesSearchService { _serviceBrand: any; private _installedExtensions: Promise; constructor( - @IInstantiationService instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService, @IEnvironmentService private readonly environmentService: IEnvironmentService, + @IInstantiationService private readonly instantiationService: IInstantiationService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService ) { - super(instantiationService); + super(); // This request goes to the shared process but results won't change during a window's lifetime, so cache the results. this._installedExtensions = this.extensionManagementService.getInstalled(ExtensionType.User).then(exts => { @@ -81,6 +86,10 @@ export class PreferencesSearchService extends LocalPreferencesSearchService impl return this.remoteSearchAllowed ? this.instantiationService.createInstance(RemoteSearchProvider, opts, this._installedExtensions) : undefined; } + + getLocalSearchProvider(filter: string): LocalSearchProvider { + return this.instantiationService.createInstance(LocalSearchProvider, filter); + } } export class LocalSearchProvider implements ISearchProvider { @@ -428,4 +437,129 @@ function remoteSettingToISetting(remoteSetting: IRemoteSetting): IExtensionSetti extensionName: remoteSetting.extensionName, extensionPublisher: remoteSetting.extensionPublisher }; -} \ No newline at end of file +} + +class SettingMatches { + + private readonly descriptionMatchingWords: Map = new Map(); + private readonly keyMatchingWords: Map = new Map(); + private readonly valueMatchingWords: Map = new Map(); + + readonly matches: IRange[]; + + constructor(searchString: string, setting: ISetting, private requireFullQueryMatch: boolean, private searchDescription: boolean, private valuesMatcher: (filter: string, setting: ISetting) => IRange[]) { + this.matches = distinct(this._findMatchesInSetting(searchString, setting), (match) => `${match.startLineNumber}_${match.startColumn}_${match.endLineNumber}_${match.endColumn}_`); + } + + private _findMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const result = this._doFindMatchesInSetting(searchString, setting); + if (setting.overrides && setting.overrides.length) { + for (const subSetting of setting.overrides) { + const subSettingMatches = new SettingMatches(searchString, subSetting, this.requireFullQueryMatch, this.searchDescription, this.valuesMatcher); + const words = searchString.split(' '); + const descriptionRanges: IRange[] = this.getRangesForWords(words, this.descriptionMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const keyRanges: IRange[] = this.getRangesForWords(words, this.keyMatchingWords, [subSettingMatches.descriptionMatchingWords, subSettingMatches.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettingKeyRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.keyMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.valueMatchingWords]); + const subSettinValueRanges: IRange[] = this.getRangesForWords(words, subSettingMatches.valueMatchingWords, [this.descriptionMatchingWords, this.keyMatchingWords, subSettingMatches.keyMatchingWords]); + result.push(...descriptionRanges, ...keyRanges, ...subSettingKeyRanges, ...subSettinValueRanges); + result.push(...subSettingMatches.matches); + } + } + return result; + } + + private _doFindMatchesInSetting(searchString: string, setting: ISetting): IRange[] { + const registry: { [qualifiedKey: string]: IJSONSchema } = Registry.as(Extensions.Configuration).getConfigurationProperties(); + const schema: IJSONSchema = registry[setting.key]; + + const words = searchString.split(' '); + const settingKeyAsWords: string = setting.key.split('.').join(' '); + + for (const word of words) { + if (this.searchDescription) { + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const descriptionMatches = matchesWords(word, setting.description[lineIndex], true); + if (descriptionMatches) { + this.descriptionMatchingWords.set(word, descriptionMatches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + } + } + + const keyMatches = or(matchesWords, matchesCamelCase)(word, settingKeyAsWords); + if (keyMatches) { + this.keyMatchingWords.set(word, keyMatches.map(match => this.toKeyRange(setting, match))); + } + + const valueMatches = typeof setting.value === 'string' ? matchesContiguousSubString(word, setting.value) : null; + if (valueMatches) { + this.valueMatchingWords.set(word, valueMatches.map(match => this.toValueRange(setting, match))); + } else if (schema && schema.enum && schema.enum.some(enumValue => typeof enumValue === 'string' && !!matchesContiguousSubString(word, enumValue))) { + this.valueMatchingWords.set(word, []); + } + } + + const descriptionRanges: IRange[] = []; + if (this.searchDescription) { + for (let lineIndex = 0; lineIndex < setting.description.length; lineIndex++) { + const matches = or(matchesContiguousSubString)(searchString, setting.description[lineIndex] || '') || []; + descriptionRanges.push(...matches.map(match => this.toDescriptionRange(setting, match, lineIndex))); + } + if (descriptionRanges.length === 0) { + descriptionRanges.push(...this.getRangesForWords(words, this.descriptionMatchingWords, [this.keyMatchingWords, this.valueMatchingWords])); + } + } + + const keyMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.key); + const keyRanges: IRange[] = keyMatches ? keyMatches.map(match => this.toKeyRange(setting, match)) : this.getRangesForWords(words, this.keyMatchingWords, [this.descriptionMatchingWords, this.valueMatchingWords]); + + let valueRanges: IRange[] = []; + if (setting.value && typeof setting.value === 'string') { + const valueMatches = or(matchesPrefix, matchesContiguousSubString)(searchString, setting.value); + valueRanges = valueMatches ? valueMatches.map(match => this.toValueRange(setting, match)) : this.getRangesForWords(words, this.valueMatchingWords, [this.keyMatchingWords, this.descriptionMatchingWords]); + } else { + valueRanges = this.valuesMatcher ? this.valuesMatcher(searchString, setting) : []; + } + + return [...descriptionRanges, ...keyRanges, ...valueRanges]; + } + + private getRangesForWords(words: string[], from: Map, others: Map[]): IRange[] { + const result: IRange[] = []; + for (const word of words) { + const ranges = from.get(word); + if (ranges) { + result.push(...ranges); + } else if (this.requireFullQueryMatch && others.every(o => !o.has(word))) { + return []; + } + } + return result; + } + + private toKeyRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.keyRange.startLineNumber, + startColumn: setting.keyRange.startColumn + match.start, + endLineNumber: setting.keyRange.startLineNumber, + endColumn: setting.keyRange.startColumn + match.end + }; + } + + private toDescriptionRange(setting: ISetting, match: IMatch, lineIndex: number): IRange { + return { + startLineNumber: setting.descriptionRanges[lineIndex].startLineNumber, + startColumn: setting.descriptionRanges[lineIndex].startColumn + match.start, + endLineNumber: setting.descriptionRanges[lineIndex].endLineNumber, + endColumn: setting.descriptionRanges[lineIndex].startColumn + match.end + }; + } + + private toValueRange(setting: ISetting, match: IMatch): IRange { + return { + startLineNumber: setting.valueRange.startLineNumber, + startColumn: setting.valueRange.startColumn + match.start + 1, + endLineNumber: setting.valueRange.startLineNumber, + endColumn: setting.valueRange.startColumn + match.end + 1 + }; + } +} diff --git a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts b/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts similarity index 99% rename from src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts rename to src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts index 775cecadca..4058ac0ba6 100644 --- a/src/vs/workbench/contrib/preferences/browser/settingsEditor2.ts +++ b/src/vs/workbench/contrib/preferences/electron-browser/settingsEditor2.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { ITreeElement } from 'vs/base/browser/ui/tree/tree'; import * as arrays from 'vs/base/common/arrays'; -import { Delayer, ThrottledDelayer, timeout } from 'vs/base/common/async'; +import { Delayer, ThrottledDelayer } from 'vs/base/common/async'; import { CancellationToken, CancellationTokenSource } from 'vs/base/common/cancellation'; import * as collections from 'vs/base/common/collections'; import { getErrorMessage, isPromiseCanceledError } from 'vs/base/common/errors'; @@ -211,7 +211,7 @@ export class SettingsEditor2 extends BaseEditor { setInput(input: SettingsEditor2Input, options: SettingsEditorOptions | null, token: CancellationToken): Promise { this.inSettingsEditorContextKey.set(true); return super.setInput(input, options, token) - .then(() => timeout(0)) // Force setInput to be async + .then(() => new Promise(process.nextTick)) // Force setInput to be async .then(() => { return this.render(token); }) @@ -251,12 +251,10 @@ export class SettingsEditor2 extends BaseEditor { } } - setOptions(options: SettingsEditorOptions | null): void { + setOptions(options: SettingsEditorOptions): void { super.setOptions(options); - if (options) { - this._setOptions(options); - } + this._setOptions(options); } private _setOptions(options: SettingsEditorOptions): void { @@ -567,7 +565,7 @@ export class SettingsEditor2 extends BaseEditor { } private createTOC(parent: HTMLElement): void { - this.tocTreeModel = this.instantiationService.createInstance(TOCTreeModel, this.viewState); + this.tocTreeModel = new TOCTreeModel(this.viewState); this.tocTreeContainer = DOM.append(parent, $('.settings-toc-container')); this.tocTree = this._register(this.instantiationService.createInstance(TOCTree, diff --git a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts index d415732c92..c63324ed97 100644 --- a/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/commandsHandler.ts @@ -30,7 +30,7 @@ import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { CancellationToken } from 'vs/base/common/cancellation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { Disposable } from 'vs/base/common/lifecycle'; import { timeout } from 'vs/base/common/async'; export const ALL_COMMANDS_PREFIX = '>'; @@ -294,7 +294,7 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { this.onBeforeRun(this.commandId); // Use a timeout to give the quick open widget a chance to close itself first - setTimeout(async () => { + setTimeout(() => { if (action && (!(action instanceof Action) || action.enabled)) { try { /* __GDPR__ @@ -304,17 +304,11 @@ abstract class BaseCommandEntry extends QuickOpenEntryGroup { } */ this.telemetryService.publicLog('workbenchActionExecuted', { id: action.id, from: 'quick open' }); - - const promise = action.run(); - if (promise) { - try { - await promise; - } finally { - if (action instanceof Action) { - action.dispose(); - } + (action.run() || Promise.resolve()).then(() => { + if (action instanceof Action) { + action.dispose(); } - } + }, err => this.onError(err)); } catch (error) { this.onError(error); } @@ -377,14 +371,12 @@ class ActionCommandEntry extends BaseCommandEntry { const wordFilter = or(matchesPrefix, matchesWords, matchesContiguousSubString); -export class CommandsHandler extends QuickOpenHandler implements IDisposable { +export class CommandsHandler extends QuickOpenHandler { static readonly ID = 'workbench.picker.commands'; private commandHistoryEnabled: boolean; - private readonly commandsHistory: CommandsHistory; - - private readonly disposables = new DisposableStore(); + private commandsHistory: CommandsHistory; private waitedForExtensionsRegistered: boolean; @@ -398,7 +390,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { ) { super(); - this.commandsHistory = this.disposables.add(this.instantiationService.createInstance(CommandsHistory)); + this.commandsHistory = this.instantiationService.createInstance(CommandsHistory); this.extensionService.whenInstalledExtensionsRegistered().then(() => this.waitedForExtensionsRegistered = true); @@ -410,7 +402,7 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { this.commandHistoryEnabled = resolveCommandHistory(this.configurationService) > 0; } - async getResults(searchValue: string, token: CancellationToken): Promise { + getResults(searchValue: string, token: CancellationToken): Promise { if (this.waitedForExtensionsRegistered) { return this.doGetResults(searchValue, token); } @@ -419,10 +411,11 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { // a chance to register so that the complete set of commands shows up as result // We do not want to delay functionality beyond that time though to keep the commands // functional. - await Promise.race([timeout(800).then(), this.extensionService.whenInstalledExtensionsRegistered()]); - this.waitedForExtensionsRegistered = true; + return Promise.race([timeout(800), this.extensionService.whenInstalledExtensionsRegistered().then(() => undefined)]).then(() => { + this.waitedForExtensionsRegistered = true; - return this.doGetResults(searchValue, token); + return this.doGetResults(searchValue, token); + }); } private doGetResults(searchValue: string, token: CancellationToken): Promise { @@ -590,10 +583,6 @@ export class CommandsHandler extends QuickOpenHandler implements IDisposable { getEmptyLabel(searchString: string): string { return nls.localize('noCommandsMatching', "No commands matching"); } - - dispose() { - this.disposables.dispose(); - } } registerEditorAction(CommandPaletteEditorAction); diff --git a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts index e04f0aa3fa..f8be9ca478 100644 --- a/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts +++ b/src/vs/workbench/contrib/quickopen/browser/gotoSymbolHandler.ts @@ -495,7 +495,7 @@ export class GotoSymbolHandler extends QuickOpenHandler { return this.cachedOutlineRequest; } - private async doGetActiveOutline(): Promise { + private doGetActiveOutline(): Promise { const activeTextEditorWidget = this.editorService.activeTextEditorWidget; if (activeTextEditorWidget) { let model = activeTextEditorWidget.getModel(); @@ -504,13 +504,13 @@ export class GotoSymbolHandler extends QuickOpenHandler { } if (model && types.isFunction((model).getLanguageIdentifier)) { - const entries = await asPromise(() => getDocumentSymbols(model, true, this.pendingOutlineRequest!.token)); - - return new OutlineModel(this.toQuickOpenEntries(entries)); + return Promise.resolve(asPromise(() => getDocumentSymbols(model, true, this.pendingOutlineRequest!.token)).then(entries => { + return new OutlineModel(this.toQuickOpenEntries(entries)); + })); } } - return null; + return Promise.resolve(null); } decorateOutline(fullRange: IRange, startRange: IRange, editor: IEditor, group: IEditorGroup): void { diff --git a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts index 3109ddeebb..abb53e72e2 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -32,7 +32,7 @@ import { LogLevelSetterChannel } from 'vs/platform/log/node/logIpc'; import { ipcRenderer as ipc } from 'electron'; import { IDiagnosticInfoOptions, IRemoteDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IProgressService, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, IProgress, IProgressStep, ProgressLocation } from 'vs/platform/progress/common/progress'; import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; @@ -143,7 +143,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc if (this.windowIndicatorEntry) { this.windowIndicatorEntry.update(properties); } else { - this.windowIndicatorEntry = this.statusbarService.addEntry(properties, 'status.host', nls.localize('status.host', "Remote Host"), StatusbarAlignment.LEFT, Number.MAX_VALUE /* first entry */); + this.windowIndicatorEntry = this.statusbarService.addEntry(properties, StatusbarAlignment.LEFT, Number.MAX_VALUE /* first entry */); } } @@ -272,7 +272,7 @@ class ProgressReporter { class RemoteAgentConnectionStatusListener implements IWorkbenchContribution { constructor( @IRemoteAgentService remoteAgentService: IRemoteAgentService, - @IProgressService progressService: IProgressService, + @IProgressService2 progressService: IProgressService2, @IDialogService dialogService: IDialogService, @ICommandService commandService: ICommandService ) { diff --git a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts index f92bd1d642..d73fa11bf0 100644 --- a/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts +++ b/src/vs/workbench/contrib/scm/browser/dirtydiffDecorator.ts @@ -7,7 +7,7 @@ import * as nls from 'vs/nls'; import 'vs/css!./media/dirtydiffDecorator'; import { ThrottledDelayer, first } from 'vs/base/common/async'; -import { IDisposable, dispose, toDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable, Disposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as ext from 'vs/workbench/common/contributions'; import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget'; @@ -184,7 +184,7 @@ class DirtyDiffWidget extends PeekViewWidget { ) { super(editor, { isResizeable: true, frameWidth: 1, keepEditorSelection: true }); - this._disposables.add(themeService.onThemeChange(this._applyTheme, this)); + themeService.onThemeChange(this._applyTheme, this, this._disposables); this._applyTheme(themeService.getTheme()); this.contextKeyService = contextKeyService.createScoped(); @@ -199,7 +199,7 @@ class DirtyDiffWidget extends PeekViewWidget { } this.setTitle(this.title); - this._disposables.add(model.onDidChange(this.renderTitle, this)); + model.onDidChange(this.renderTitle, this, this._disposables); } showChange(index: number): void { @@ -253,8 +253,8 @@ class DirtyDiffWidget extends PeekViewWidget { const previous = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowPreviousChangeAction(), 'show-previous-change chevron-up'); const next = this.instantiationService.createInstance(UIEditorAction, this.editor, new ShowNextChangeAction(), 'show-next-change chevron-down'); - this._disposables.add(previous); - this._disposables.add(next); + this._disposables.push(previous); + this._disposables.push(next); this._actionbarWidget.push([previous, next], { label: false, icon: true }); const actions: IAction[] = []; @@ -554,7 +554,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ } }); -export class DirtyDiffController extends Disposable implements IEditorContribution { +export class DirtyDiffController implements IEditorContribution { private static readonly ID = 'editor.contrib.dirtydiff'; @@ -571,20 +571,20 @@ export class DirtyDiffController extends Disposable implements IEditorContributi private session: IDisposable = Disposable.None; private mouseDownInfo: { lineNumber: number } | null = null; private enabled = false; + private disposables: IDisposable[] = []; constructor( private editor: ICodeEditor, @IContextKeyService contextKeyService: IContextKeyService, @IInstantiationService private readonly instantiationService: IInstantiationService ) { - super(); this.enabled = !contextKeyService.getContextKeyValue('isInDiffEditor'); if (this.enabled) { this.isDirtyDiffVisible = isDirtyDiffVisible.bindTo(contextKeyService); - this._register(editor.onMouseDown(e => this.onEditorMouseDown(e))); - this._register(editor.onMouseUp(e => this.onEditorMouseUp(e))); - this._register(editor.onDidChangeModel(() => this.close())); + this.disposables.push(editor.onMouseDown(e => this.onEditorMouseDown(e))); + this.disposables.push(editor.onMouseUp(e => this.onEditorMouseUp(e))); + this.disposables.push(editor.onDidChangeModel(() => this.close())); } } @@ -674,20 +674,22 @@ export class DirtyDiffController extends Disposable implements IEditorContributi this.widget = this.instantiationService.createInstance(DirtyDiffWidget, this.editor, model); this.isDirtyDiffVisible.set(true); - const disposables = new DisposableStore(); - disposables.add(Event.once(this.widget.onDidClose)(this.close, this)); - disposables.add(model.onDidChange(this.onDidModelChange, this)); + const disposables: IDisposable[] = []; + Event.once(this.widget.onDidClose)(this.close, this, disposables); + model.onDidChange(this.onDidModelChange, this, disposables); - disposables.add(this.widget); - disposables.add(toDisposable(() => { - this.model = null; - this.widget = null; - this.currentIndex = -1; - this.isDirtyDiffVisible.set(false); - this.editor.focus(); - })); + disposables.push( + this.widget, + toDisposable(() => { + this.model = null; + this.widget = null; + this.currentIndex = -1; + this.isDirtyDiffVisible.set(false); + this.editor.focus(); + }) + ); - this.session = disposables; + this.session = combinedDisposable(disposables); return true; } @@ -806,6 +808,10 @@ export class DirtyDiffController extends Disposable implements IEditorContributi return model.changes; } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export const editorGutterModifiedBackground = registerColor('editorGutter.modifiedBackground', { @@ -831,7 +837,7 @@ export const overviewRulerModifiedForeground = registerColor('editorOverviewRule export const overviewRulerAddedForeground = registerColor('editorOverviewRuler.addedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerAddedForeground', 'Overview ruler marker color for added content.')); export const overviewRulerDeletedForeground = registerColor('editorOverviewRuler.deletedForeground', { dark: overviewRulerDefault, light: overviewRulerDefault, hc: overviewRulerDefault }, nls.localize('overviewRulerDeletedForeground', 'Overview ruler marker color for deleted content.')); -class DirtyDiffDecorator extends Disposable { +class DirtyDiffDecorator { static createDecoration(className: string, foregroundColor: string, options: { gutter: boolean, overview: boolean, isWholeLine: boolean }): ModelDecorationOptions { const decorationOptions: IModelDecorationOptions = { @@ -856,6 +862,7 @@ class DirtyDiffDecorator extends Disposable { private addedOptions: ModelDecorationOptions; private deletedOptions: ModelDecorationOptions; private decorations: string[] = []; + private disposables: IDisposable[] = []; private editorModel: ITextModel | null; constructor( @@ -863,7 +870,6 @@ class DirtyDiffDecorator extends Disposable { private model: DirtyDiffModel, @IConfigurationService configurationService: IConfigurationService ) { - super(); this.editorModel = editorModel; const decorations = configurationService.getValue('scm.diffDecorations'); const gutter = decorations === 'all' || decorations === 'gutter'; @@ -874,7 +880,7 @@ class DirtyDiffDecorator extends Disposable { this.addedOptions = DirtyDiffDecorator.createDecoration('dirty-diff-added', overviewRulerAddedForeground, options); this.deletedOptions = DirtyDiffDecorator.createDecoration('dirty-diff-deleted', overviewRulerDeletedForeground, { ...options, isWholeLine: false }); - this._register(model.onDidChange(this.onDidChange, this)); + model.onDidChange(this.onDidChange, this, this.disposables); } private onDidChange(): void { @@ -918,7 +924,7 @@ class DirtyDiffDecorator extends Disposable { } dispose(): void { - super.dispose(); + this.disposables = dispose(this.disposables); if (this.editorModel && !this.editorModel.isDisposed()) { this.editorModel.deltaDecorations(this.decorations, []); @@ -951,7 +957,7 @@ function compareChanges(a: IChange, b: IChange): number { return a.originalEndLineNumber - b.originalEndLineNumber; } -export class DirtyDiffModel extends Disposable { +export class DirtyDiffModel { private _originalModel: ITextModel | null; get original(): ITextModel | null { return this._originalModel; } @@ -959,8 +965,9 @@ export class DirtyDiffModel extends Disposable { private diffDelayer: ThrottledDelayer | null; private _originalURIPromise?: Promise; - private repositoryDisposables = new Set(); - private readonly originalModelDisposables = this._register(new DisposableStore()); + private repositoryDisposables = new Set(); + private originalModelDisposables: IDisposable[] = []; + private disposables: IDisposable[] = []; private _onDidChange = new Emitter[]>(); readonly onDidChange: Event[]> = this._onDidChange.event; @@ -978,28 +985,27 @@ export class DirtyDiffModel extends Disposable { @IEditorWorkerService private readonly editorWorkerService: IEditorWorkerService, @ITextModelService private readonly textModelResolverService: ITextModelService ) { - super(); this._editorModel = editorModel; this.diffDelayer = new ThrottledDelayer(200); - this._register(editorModel.onDidChangeContent(() => this.triggerDiff())); - this._register(scmService.onDidAddRepository(this.onDidAddRepository, this)); + this.disposables.push(editorModel.onDidChangeContent(() => this.triggerDiff())); + scmService.onDidAddRepository(this.onDidAddRepository, this, this.disposables); scmService.repositories.forEach(r => this.onDidAddRepository(r)); this.triggerDiff(); } private onDidAddRepository(repository: ISCMRepository): void { - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; this.repositoryDisposables.add(disposables); - disposables.add(toDisposable(() => this.repositoryDisposables.delete(disposables))); + disposables.push(toDisposable(() => this.repositoryDisposables.delete(disposables))); const onDidChange = Event.any(repository.provider.onDidChange, repository.provider.onDidChangeResources); - disposables.add(onDidChange(this.triggerDiff, this)); + onDidChange(this.triggerDiff, this, disposables); const onDidRemoveThis = Event.filter(this.scmService.onDidRemoveRepository, r => r === repository); - disposables.add(onDidRemoveThis(() => dispose(disposables), null)); + onDidRemoveThis(() => dispose(disposables), null, disposables); this.triggerDiff(); } @@ -1069,9 +1075,12 @@ export class DirtyDiffModel extends Disposable { this._originalModel = ref.object.textEditorModel; - this.originalModelDisposables.clear(); - this.originalModelDisposables.add(ref); - this.originalModelDisposables.add(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); + const originalModelDisposables: IDisposable[] = []; + originalModelDisposables.push(ref); + originalModelDisposables.push(ref.object.textEditorModel.onDidChangeContent(() => this.triggerDiff())); + + dispose(this.originalModelDisposables); + this.originalModelDisposables = originalModelDisposables; return originalUri; }); @@ -1128,7 +1137,8 @@ export class DirtyDiffModel extends Disposable { } dispose(): void { - super.dispose(); + this.originalModelDisposables = dispose(this.originalModelDisposables); + this.disposables = dispose(this.disposables); this._editorModel = null; this._originalModel = null; @@ -1153,25 +1163,25 @@ class DirtyDiffItem { } } -export class DirtyDiffWorkbenchController extends Disposable implements ext.IWorkbenchContribution, IModelRegistry { +export class DirtyDiffWorkbenchController implements ext.IWorkbenchContribution, IModelRegistry { private enabled = false; private models: ITextModel[] = []; private items: { [modelId: string]: DirtyDiffItem; } = Object.create(null); private transientDisposables: IDisposable[] = []; private stylesheet: HTMLStyleElement; + private disposables: IDisposable[] = []; constructor( @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IConfigurationService private readonly configurationService: IConfigurationService ) { - super(); this.stylesheet = createStyleSheet(); - this._register(toDisposable(() => this.stylesheet.parentElement!.removeChild(this.stylesheet))); + this.disposables.push(toDisposable(() => this.stylesheet.parentElement!.removeChild(this.stylesheet))); const onDidChangeConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorations')); - this._register(onDidChangeConfiguration(this.onDidChangeConfiguration, this)); + onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); this.onDidChangeConfiguration(); const onDidChangeDiffWidthConfiguration = Event.filter(configurationService.onDidChangeConfiguration, e => e.affectsConfiguration('scm.diffDecorationsGutterWidth')); @@ -1274,7 +1284,7 @@ export class DirtyDiffWorkbenchController extends Disposable implements ext.IWor dispose(): void { this.disable(); - super.dispose(); + this.disposables = dispose(this.disposables); } } diff --git a/src/vs/workbench/contrib/scm/browser/scmActivity.ts b/src/vs/workbench/contrib/scm/browser/scmActivity.ts index a6d45f8a96..89b988b193 100644 --- a/src/vs/workbench/contrib/scm/browser/scmActivity.ts +++ b/src/vs/workbench/contrib/scm/browser/scmActivity.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { basename } from 'vs/base/common/resources'; -import { IDisposable, dispose, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { VIEWLET_ID, ISCMService, ISCMRepository } from 'vs/workbench/contrib/scm/common/scm'; import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; @@ -46,7 +46,7 @@ export class StatusUpdater implements IWorkbenchContribution { this.render(); }); - const disposable = combinedDisposable(changeDisposable, removeDisposable); + const disposable = combinedDisposable([changeDisposable, removeDisposable]); this.disposables.push(disposable); } @@ -151,7 +151,7 @@ export class StatusBarController implements IWorkbenchContribution { } }); - const disposable = combinedDisposable(changeDisposable, removeDisposable); + const disposable = combinedDisposable([changeDisposable, removeDisposable]); this.disposables.push(disposable); if (!this.focusedRepository) { @@ -187,17 +187,14 @@ export class StatusBarController implements IWorkbenchContribution { ? `${basename(repository.provider.rootUri)} (${repository.provider.label})` : repository.provider.label; - const disposables = new DisposableStore(); - for (const c of commands) { - disposables.add(this.statusbarService.addEntry({ - text: c.title, - tooltip: `${label} - ${c.tooltip}`, - command: c.id, - arguments: c.arguments - }, 'status.scm', localize('status.scm', "Source Control"), MainThreadStatusBarAlignment.LEFT, 10000)); - } + const disposables = commands.map(c => this.statusbarService.addEntry({ + text: c.title, + tooltip: `${label} - ${c.tooltip}`, + command: c.id, + arguments: c.arguments + }, MainThreadStatusBarAlignment.LEFT, 10000)); - this.statusBarDisposable = disposables; + this.statusBarDisposable = combinedDisposable(disposables); } dispose(): void { diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index f83c1add20..83199b384f 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -8,7 +8,7 @@ import { localize } from 'vs/nls'; import { Event, Emitter } from 'vs/base/common/event'; import { domEvent } from 'vs/base/browser/event'; import { basename } from 'vs/base/common/resources'; -import { IDisposable, dispose, Disposable, DisposableStore, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, combinedDisposable, Disposable } from 'vs/base/common/lifecycle'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { append, $, addClass, toggleClass, trackFocus, removeClass, addClasses } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -162,14 +162,14 @@ class ProviderRenderer implements IListRenderer new StatusBarActionViewItem(a as StatusBarAction) }); const disposable = Disposable.None; - const templateDisposable = combinedDisposable(actionBar, badgeStyler); + const templateDisposable = combinedDisposable([actionBar, badgeStyler]); return { title, type, countContainer, count, actionBar, disposable, templateDisposable }; } renderElement(repository: ISCMRepository, index: number, templateData: RepositoryTemplateData): void { templateData.disposable.dispose(); - const disposables = new DisposableStore(); + const disposables: IDisposable[] = []; if (repository.provider.rootUri) { templateData.title.textContent = basename(repository.provider.rootUri); @@ -181,7 +181,7 @@ class ProviderRenderer implements IListRenderer dispose(actions); - disposables.add({ dispose: disposeActions }); + disposables.push({ dispose: disposeActions }); const update = () => { disposeActions(); @@ -198,10 +198,10 @@ class ProviderRenderer implements IListRenderer; - this._register(renderer.onDidRenderElement(e => this.list.updateWidth(this.viewModel.repositories.indexOf(e)), null)); - this._register(this.list.onSelectionChange(this.onListSelectionChange, this)); - this._register(this.list.onFocusChange(this.onListFocusChange, this)); - this._register(this.list.onContextMenu(this.onListContextMenu, this)); + renderer.onDidRenderElement(e => this.list.updateWidth(this.viewModel.repositories.indexOf(e)), null, this.disposables); + this.list.onSelectionChange(this.onListSelectionChange, this, this.disposables); + this.list.onFocusChange(this.onListFocusChange, this, this.disposables); + this.list.onContextMenu(this.onListContextMenu, this, this.disposables); - this._register(this.viewModel.onDidChangeVisibleRepositories(this.updateListSelection, this)); + this.viewModel.onDidChangeVisibleRepositories(this.updateListSelection, this, this.disposables); - this._register(this.viewModel.onDidSplice(({ index, deleteCount, elements }) => this.splice(index, deleteCount, elements), null)); + this.viewModel.onDidSplice(({ index, deleteCount, elements }) => this.splice(index, deleteCount, elements), null, this.disposables); this.splice(0, 0, this.viewModel.repositories); - this._register(this.list); + this.disposables.push(this.list); - this._register(this.configurationService.onDidChangeConfiguration(e => { + this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('scm.providers.visible')) { this.updateBodySize(); } - })); + }, this.disposables); this.updateListSelection(); } @@ -396,14 +396,14 @@ class ResourceGroupRenderer implements IListRenderer template.count.setCount(group.elements.length); - disposables.add(group.onDidSplice(updateCount, null)); + group.onDidSplice(updateCount, null, disposables); updateCount(); - template.elementDisposable = disposables; + template.elementDisposable = combinedDisposable(disposables); } disposeElement(group: ISCMResourceGroup, index: number, template: ResourceGroupTemplate): void { @@ -489,8 +489,8 @@ class ResourceRenderer implements IListRenderer template.fileLabel.setFile(resource.sourceUri, { fileDecorations: { colors: false, badges: !icon, data: resource.decorations } }); template.actionBar.context = resource; - const disposables = new DisposableStore(); - disposables.add(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resource.resourceGroup), template.actionBar)); + const disposables: IDisposable[] = []; + disposables.push(connectPrimaryMenuToInlineActionBar(this.menus.getResourceMenu(resource.resourceGroup), template.actionBar)); toggleClass(template.name, 'strike-through', resource.decorations.strikeThrough); toggleClass(template.element, 'faded', resource.decorations.faded); @@ -505,7 +505,7 @@ class ResourceRenderer implements IListRenderer } template.element.setAttribute('data-tooltip', resource.decorations.tooltip || ''); - template.elementDisposable = disposables; + template.elementDisposable = combinedDisposable(disposables); } disposeElement(resource: ISCMResource, index: number, template: ResourceTemplate): void { @@ -602,10 +602,10 @@ class ResourceGroupSplicer { absoluteToInsert.push(element); } - const disposable = combinedDisposable( + const disposable = combinedDisposable([ group.onDidChange(() => this.onDidChangeGroup(group)), group.onDidSplice(splice => this.onDidSpliceGroup(group, splice)) - ); + ]); itemsToInsert.push({ group, visible, disposable }); } @@ -699,7 +699,6 @@ export class RepositoryPanel extends ViewletPanel { private cachedHeight: number | undefined = undefined; private cachedWidth: number | undefined = undefined; - private cachedScrollTop: number | undefined = undefined; private inputBoxContainer: HTMLElement; private inputBox: InputBox; private listContainer: HTMLElement; @@ -728,8 +727,8 @@ export class RepositoryPanel extends ViewletPanel { super(options, keybindingService, contextMenuService, configurationService); this.menus = instantiationService.createInstance(SCMMenus, this.repository.provider); - this._register(this.menus); - this._register(this.menus.onDidChangeTitle(this._onDidChangeTitleArea.fire, this._onDidChangeTitleArea)); + this.disposables.push(this.menus); + this.menus.onDidChangeTitle(this._onDidChangeTitleArea.fire, this._onDidChangeTitleArea, this.disposables); this.contextKeyService = contextKeyService.createScoped(this.element); this.contextKeyService.createKey('scmRepository', this.repository); @@ -737,7 +736,7 @@ export class RepositoryPanel extends ViewletPanel { render(): void { super.render(); - this._register(this.menus.onDidChangeTitle(this.updateActions, this)); + this.menus.onDidChangeTitle(this.updateActions, this, this.disposables); } protected renderHeaderTitle(container: HTMLElement): void { @@ -759,8 +758,8 @@ export class RepositoryPanel extends ViewletPanel { protected renderBody(container: HTMLElement): void { const focusTracker = trackFocus(container); - this._register(focusTracker.onDidFocus(() => this.repository.focus())); - this._register(focusTracker); + this.disposables.push(focusTracker.onDidFocus(() => this.repository.focus())); + this.disposables.push(focusTracker); // Input this.inputBoxContainer = append(container, $('.scm-editor')); @@ -790,33 +789,33 @@ export class RepositoryPanel extends ViewletPanel { this.inputBox = new InputBox(this.inputBoxContainer, this.contextViewService, { flexibleHeight: true }); this.inputBox.setEnabled(this.isBodyVisible()); - this._register(attachInputBoxStyler(this.inputBox, this.themeService)); - this._register(this.inputBox); + this.disposables.push(attachInputBoxStyler(this.inputBox, this.themeService)); + this.disposables.push(this.inputBox); - this._register(this.inputBox.onDidChange(triggerValidation, null)); + this.inputBox.onDidChange(triggerValidation, null, this.disposables); const onKeyUp = domEvent(this.inputBox.inputElement, 'keyup'); const onMouseUp = domEvent(this.inputBox.inputElement, 'mouseup'); - this._register(Event.any(onKeyUp, onMouseUp)(triggerValidation, null)); + Event.any(onKeyUp, onMouseUp)(triggerValidation, null, this.disposables); this.inputBox.value = this.repository.input.value; - this._register(this.inputBox.onDidChange(value => this.repository.input.value = value, null)); - this._register(this.repository.input.onDidChange(value => this.inputBox.value = value, null)); + this.inputBox.onDidChange(value => this.repository.input.value = value, null, this.disposables); + this.repository.input.onDidChange(value => this.inputBox.value = value, null, this.disposables); updatePlaceholder(); - this._register(this.repository.input.onDidChangePlaceholder(updatePlaceholder, null)); - this._register(this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null)); + this.repository.input.onDidChangePlaceholder(updatePlaceholder, null, this.disposables); + this.keybindingService.onDidUpdateKeybindings(updatePlaceholder, null, this.disposables); - this._register(this.inputBox.onDidHeightChange(() => this.layoutBody())); + this.disposables.push(this.inputBox.onDidHeightChange(() => this.layoutBody())); if (this.repository.provider.onDidChangeCommitTemplate) { - this._register(this.repository.provider.onDidChangeCommitTemplate(this.updateInputBox, this)); + this.repository.provider.onDidChangeCommitTemplate(this.updateInputBox, this, this.disposables); } this.updateInputBox(); // Input box visibility - this._register(this.repository.input.onDidChangeVisibility(this.updateInputBoxVisibility, this)); + this.repository.input.onDidChangeVisibility(this.updateInputBoxVisibility, this, this.disposables); this.updateInputBoxVisibility(); // List @@ -831,7 +830,7 @@ export class RepositoryPanel extends ViewletPanel { const actionViewItemProvider = (action: IAction) => this.getActionViewItem(action); this.listLabels = this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility }); - this._register(this.listLabels); + this.disposables.push(this.listLabels); const renderers = [ new ResourceGroupRenderer(actionViewItemProvider, this.themeService, this.menus), @@ -844,20 +843,20 @@ export class RepositoryPanel extends ViewletPanel { horizontalScrolling: false }) as WorkbenchList; - this._register(Event.chain(this.list.onDidOpen) + Event.chain(this.list.onDidOpen) .map(e => e.elements[0]) .filter(e => !!e && isSCMResource(e)) - .on(this.open, this)); + .on(this.open, this, this.disposables); - this._register(Event.chain(this.list.onPin) + Event.chain(this.list.onPin) .map(e => e.elements[0]) .filter(e => !!e && isSCMResource(e)) - .on(this.pin, this)); + .on(this.pin, this, this.disposables); - this._register(this.list.onContextMenu(this.onListContextMenu, this)); - this._register(this.list); + this.list.onContextMenu(this.onListContextMenu, this, this.disposables); + this.disposables.push(this.list); - this._register(this.viewModel.onDidChangeVisibility(this.onDidChangeVisibility, this)); + this.viewModel.onDidChangeVisibility(this.onDidChangeVisibility, this, this.disposables); this.onDidChangeVisibility(this.viewModel.isVisible()); this.onDidChangeBodyVisibility(visible => this.inputBox.setEnabled(visible)); } @@ -867,7 +866,6 @@ export class RepositoryPanel extends ViewletPanel { const listSplicer = new ResourceGroupSplicer(this.repository.provider.groups, this.list); this.visibilityDisposables.push(listSplicer); } else { - this.cachedScrollTop = this.list.scrollTop; this.visibilityDisposables = dispose(this.visibilityDisposables); } } @@ -896,13 +894,6 @@ export class RepositoryPanel extends ViewletPanel { this.listContainer.style.height = `${height}px`; this.list.layout(height, width); } - - if (this.cachedScrollTop !== undefined && this.list.scrollTop !== this.cachedScrollTop) { - this.list.scrollTop = Math.min(this.cachedScrollTop, this.list.scrollHeight); - // Applying the cached scroll position just once until the next leave. - // This, also, avoids the scrollbar to flicker when resizing the sidebar. - this.cachedScrollTop = undefined; - } } focus(): void { @@ -1115,15 +1106,15 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { super(VIEWLET_ID, SCMViewlet.STATE_KEY, true, configurationService, layoutService, telemetryService, storageService, instantiationService, themeService, contextMenuService, extensionService, contextService); this.menus = instantiationService.createInstance(SCMMenus, undefined); - this._register(this.menus.onDidChangeTitle(this.updateTitleArea, this)); + this.menus.onDidChangeTitle(this.updateTitleArea, this, this.toDispose); this.message = $('.empty-message', { tabIndex: 0 }, localize('no open repo', "No source control providers registered.")); - this._register(configurationService.onDidChangeConfiguration(e => { + configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('scm.alwaysShowProviders')) { this.onDidChangeRepositories(); } - })); + }, this.toDispose); } create(parent: HTMLElement): void { @@ -1133,8 +1124,8 @@ export class SCMViewlet extends ViewContainerViewlet implements IViewModel { addClasses(parent, 'scm-viewlet', 'empty'); append(parent, this.message); - this._register(this.scmService.onDidAddRepository(this.onDidAddRepository, this)); - this._register(this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this)); + this.scmService.onDidAddRepository(this.onDidAddRepository, this, this.toDispose); + this.scmService.onDidRemoveRepository(this.onDidRemoveRepository, this, this.toDispose); this.scmService.repositories.forEach(r => this.onDidAddRepository(r)); } diff --git a/src/vs/workbench/contrib/search/browser/openFileHandler.ts b/src/vs/workbench/contrib/search/browser/openFileHandler.ts index 9e08445143..24a03d6887 100644 --- a/src/vs/workbench/contrib/search/browser/openFileHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openFileHandler.ts @@ -117,6 +117,7 @@ export class OpenFileHandler extends QuickOpenHandler { private cacheState: CacheState; constructor( + @IEditorService private readonly editorService: IEditorService, @IInstantiationService private readonly instantiationService: IInstantiationService, @IWorkbenchThemeService private readonly themeService: IWorkbenchThemeService, @IWorkspaceContextService private readonly contextService: IWorkspaceContextService, @@ -207,7 +208,7 @@ export class OpenFileHandler extends QuickOpenHandler { private doResolveQueryOptions(query: IPreparedQuery, cacheKey?: string, maxSortedResults?: number): IFileQueryBuilderOptions { const queryOptions: IFileQueryBuilderOptions = { _reason: 'openFileHandler', - extraFileResources: this.instantiationService.invokeFunction(getOutOfWorkspaceEditorResources), + extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService), filePattern: query.original, cacheKey }; @@ -232,7 +233,7 @@ export class OpenFileHandler extends QuickOpenHandler { private cacheQuery(cacheKey: string): IFileQuery { const options: IFileQueryBuilderOptions = { _reason: 'openFileHandler', - extraFileResources: this.instantiationService.invokeFunction(getOutOfWorkspaceEditorResources), + extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService), filePattern: '', cacheKey: cacheKey, maxResults: 0, diff --git a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts index 0bd9ec0e2b..805d0b3b07 100644 --- a/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts +++ b/src/vs/workbench/contrib/search/browser/openSymbolHandler.ts @@ -156,12 +156,12 @@ export class OpenSymbolHandler extends QuickOpenHandler { return true; } - async getResults(searchValue: string, token: CancellationToken): Promise { + getResults(searchValue: string, token: CancellationToken): Promise { searchValue = searchValue.trim(); - let entries: QuickOpenEntry[]; + let promise: Promise; if (!this.options.skipDelay) { - entries = await this.delayer.trigger(() => { + promise = this.delayer.trigger(() => { if (token.isCancellationRequested) { return Promise.resolve([]); } @@ -169,31 +169,32 @@ export class OpenSymbolHandler extends QuickOpenHandler { return this.doGetResults(searchValue, token); }); } else { - entries = await this.doGetResults(searchValue, token); + promise = this.doGetResults(searchValue, token); } - return new QuickOpenModel(entries); + return promise.then(e => new QuickOpenModel(e)); } - private async doGetResults(searchValue: string, token: CancellationToken): Promise { - const tuples = await getWorkspaceSymbols(searchValue, token); - if (token.isCancellationRequested) { - return []; - } + private doGetResults(searchValue: string, token: CancellationToken): Promise { + return getWorkspaceSymbols(searchValue, token).then(tuples => { + if (token.isCancellationRequested) { + return []; + } - const result: SymbolEntry[] = []; - for (let tuple of tuples) { - const [provider, bearings] = tuple; - this.fillInSymbolEntries(result, provider, bearings, searchValue); - } + const result: SymbolEntry[] = []; + for (let tuple of tuples) { + const [provider, bearings] = tuple; + this.fillInSymbolEntries(result, provider, bearings, searchValue); + } - // Sort (Standalone only) - if (!this.options.skipSorting) { - searchValue = searchValue ? strings.stripWildcards(searchValue.toLowerCase()) : searchValue; - return result.sort((a, b) => SymbolEntry.compare(a, b, searchValue)); - } + // Sort (Standalone only) + if (!this.options.skipSorting) { + searchValue = searchValue ? strings.stripWildcards(searchValue.toLowerCase()) : searchValue; + return result.sort((a, b) => SymbolEntry.compare(a, b, searchValue)); + } - return result; + return result; + }); } private fillInSymbolEntries(bucket: SymbolEntry[], provider: IWorkspaceSymbolProvider, types: IWorkspaceSymbol[], searchValue: string): void { diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 1048017e2e..479fe98b79 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -33,8 +33,8 @@ import { FileChangesEvent, FileChangeType, IFileService } from 'vs/platform/file import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { TreeResourceNavigator2, WorkbenchObjectTree, getSelectionKeyboardEvent } from 'vs/platform/list/browser/listService'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { ILocalProgressService, IProgressService } from 'vs/platform/progress/common/progress'; -import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, SearchErrorCode, VIEW_ID, VIEWLET_ID } from 'vs/workbench/services/search/common/search'; +import { IProgressService } from 'vs/platform/progress/common/progress'; +import { IPatternInfo, ISearchComplete, ISearchConfiguration, ISearchConfigurationProperties, ITextQuery, SearchErrorCode, VIEW_ID } from 'vs/workbench/services/search/common/search'; import { ISearchHistoryService, ISearchHistoryValues } from 'vs/workbench/contrib/search/common/searchHistoryService'; import { diffInserted, diffInsertedOutline, diffRemoved, diffRemovedOutline, editorFindMatchHighlight, editorFindMatchHighlightBorder, listActiveSelectionForeground } from 'vs/platform/theme/common/colorRegistry'; import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; @@ -59,7 +59,7 @@ import { relativePath } from 'vs/base/common/resources'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { ViewletPanel, IViewletPanelOptions } from 'vs/workbench/browser/parts/views/panelViewlet'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { Memento, MementoObject } from 'vs/workbench/common/memento'; +import { Memento } from 'vs/workbench/common/memento'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; const $ = dom.$; @@ -102,8 +102,8 @@ export class SearchView extends ViewletPanel { private tree: WorkbenchObjectTree; private treeLabels: ResourceLabels; - private viewletState: MementoObject; - private globalMemento: MementoObject; + private viewletState: object; + private globalMemento: object; private messagesElement: HTMLElement; private messageDisposables: IDisposable[] = []; private searchWidgetsContainerElement: HTMLElement; @@ -129,7 +129,6 @@ export class SearchView extends ViewletPanel { options: IViewletPanelOptions, @IFileService private readonly fileService: IFileService, @IEditorService private readonly editorService: IEditorService, - @ILocalProgressService private readonly localProgressService: ILocalProgressService, @IProgressService private readonly progressService: IProgressService, @INotificationService private readonly notificationService: INotificationService, @IDialogService private readonly dialogService: IDialogService, @@ -518,7 +517,7 @@ export class SearchView extends ViewletPanel { return; } - const progressRunner = this.localProgressService.show(100); + const progressRunner = this.progressService.show(100); const occurrences = this.viewModel.searchResult.count(); const fileCount = this.viewModel.searchResult.fileCount(); @@ -1194,7 +1193,7 @@ export class SearchView extends ViewletPanel { const options: ITextQueryBuilderOptions = { _reason: 'searchView', - extraFileResources: this.instantiationService.invokeFunction(getOutOfWorkspaceEditorResources), + extraFileResources: getOutOfWorkspaceEditorResources(this.editorService, this.contextService), maxResults: SearchView.MAX_TEXT_RESULTS, disregardIgnoreFiles: !useExcludesAndIgnoreFiles || undefined, disregardExcludeSettings: !useExcludesAndIgnoreFiles || undefined, @@ -1266,10 +1265,7 @@ export class SearchView extends ViewletPanel { } private doSearch(query: ITextQuery, options: ITextQueryBuilderOptions, excludePatternText: string, includePatternText: string): Thenable { - let progressComplete: () => void; - this.progressService.withProgress({ location: VIEWLET_ID }, _progress => { - return new Promise(resolve => progressComplete = resolve); - }); + const progressRunner = this.progressService.show(/*infinite=*/true); this.searchWidget.searchInput.clearMessage(); this.searching = true; @@ -1284,7 +1280,7 @@ export class SearchView extends ViewletPanel { this.searching = false; // Complete up to 100% as needed - progressComplete(); + progressRunner.done(); // Do final render, then expand if just 1 file with less than 50 matches this.onSearchResultsChanged(); @@ -1379,7 +1375,7 @@ export class SearchView extends ViewletPanel { } else { this.searching = false; this.updateActions(); - progressComplete(); + progressRunner.done(); this.searchWidget.searchInput.showMessage({ content: e.message, type: MessageType.ERROR }); this.viewModel.searchResult.clear(); @@ -1511,7 +1507,7 @@ export class SearchView extends ViewletPanel { this.searchWithoutFolderMessageElement = this.clearMessage(); const textEl = dom.append(this.searchWithoutFolderMessageElement, - $('p', undefined, nls.localize('searchWithoutFolder', "You have not opened or specified a folder. Only open files are currently searched - "))); + $('p', undefined, nls.localize('searchWithoutFolder', "You have not yet opened a folder. Only open files are currently searched - "))); const openFolderLink = dom.append(textEl, $('a.pointer.prominent', { tabindex: 0 }, nls.localize('openFolder', "Open Folder"))); @@ -1699,9 +1695,21 @@ export class SearchView extends ViewletPanel { super.saveState(); } + private _toDispose: IDisposable[] = []; + protected _register(t: T): T { + if (this.isDisposed) { + console.warn('Registering disposable on object that has already been disposed.'); + t.dispose(); + } else { + this._toDispose.push(t); + } + return t; + } + dispose(): void { this.isDisposed = true; this.saveState(); + this._toDispose = dispose(this._toDispose); super.dispose(); } } diff --git a/src/vs/workbench/contrib/search/common/queryBuilder.ts b/src/vs/workbench/contrib/search/common/queryBuilder.ts index 534d110295..938b52c856 100644 --- a/src/vs/workbench/contrib/search/common/queryBuilder.ts +++ b/src/vs/workbench/contrib/search/common/queryBuilder.ts @@ -288,7 +288,7 @@ export class QueryBuilder { globPortion = normalizeGlobPattern(globPortion); } - // One pathPortion to multiple expanded search paths (e.g. duplicate matching workspace folders) + // One pathPortion to multiple expanded search paths (eg duplicate matching workspace folders) const oneExpanded = this.expandOneSearchPath(pathPortion); // Expanded search paths to multiple resolved patterns (with ** and without) diff --git a/src/vs/workbench/contrib/search/common/search.ts b/src/vs/workbench/contrib/search/common/search.ts index 8238a18210..3391de2a52 100644 --- a/src/vs/workbench/contrib/search/common/search.ts +++ b/src/vs/workbench/contrib/search/common/search.ts @@ -12,8 +12,6 @@ import { URI } from 'vs/base/common/uri'; import { toResource, SideBySideEditor } from 'vs/workbench/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { CancellationToken } from 'vs/base/common/cancellation'; -import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; -import { IFileService } from 'vs/platform/files/common/files'; export interface IWorkspaceSymbol { name: string; @@ -83,14 +81,15 @@ export interface IWorkbenchSearchConfiguration extends ISearchConfiguration { /** * Helper to return all opened editors with resources not belonging to the currently opened workspace. */ -export function getOutOfWorkspaceEditorResources(accessor: ServicesAccessor): URI[] { - const editorService = accessor.get(IEditorService); - const contextService = accessor.get(IWorkspaceContextService); - const fileService = accessor.get(IFileService); +export function getOutOfWorkspaceEditorResources(editorService: IEditorService, contextService: IWorkspaceContextService): URI[] { + const resources: URI[] = []; - const resources = editorService.editors - .map(editor => toResource(editor, { supportSideBySide: SideBySideEditor.MASTER })) - .filter(resource => !!resource && !contextService.isInsideWorkspace(resource) && fileService.canHandleResource(resource)); + editorService.editors.forEach(editor => { + const resource = toResource(editor, { supportSideBySide: SideBySideEditor.MASTER }); + if (resource && !contextService.isInsideWorkspace(resource)) { + resources.push(resource); + } + }); - return resources as URI[]; + return resources; } diff --git a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts index b1a44831b9..dd1759d308 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippets.contribution.ts @@ -43,7 +43,7 @@ const languageScopeSchema: IJSONSchema = { type: ['string', 'array'] }, body: { - description: nls.localize('snippetSchema.json.body', 'The snippet content. Use \'$1\', \'${1:defaultText}\' to define cursor positions, use \'$0\' for the final cursor position. Insert variable values with \'${varName}\' and \'${varName:defaultText}\', e.g. \'This is file: $TM_FILENAME\'.'), + description: nls.localize('snippetSchema.json.body', 'The snippet content. Use \'$1\', \'${1:defaultText}\' to define cursor positions, use \'$0\' for the final cursor position. Insert variable values with \'${varName}\' and \'${varName:defaultText}\', e.g \'This is file: $TM_FILENAME\'.'), type: ['string', 'array'], items: { type: 'string' @@ -78,11 +78,11 @@ const globalSchema: IJSONSchema = { type: ['string', 'array'] }, scope: { - description: nls.localize('snippetSchema.json.scope', "A list of language names to which this snippet applies, e.g. 'typescript,javascript'."), + description: nls.localize('snippetSchema.json.scope', "A list of language names to which this snippet applies, e.g 'typescript,javascript'."), type: 'string' }, body: { - description: nls.localize('snippetSchema.json.body', 'The snippet content. Use \'$1\', \'${1:defaultText}\' to define cursor positions, use \'$0\' for the final cursor position. Insert variable values with \'${varName}\' and \'${varName:defaultText}\', e.g. \'This is file: $TM_FILENAME\'.'), + description: nls.localize('snippetSchema.json.body', 'The snippet content. Use \'$1\', \'${1:defaultText}\' to define cursor positions, use \'$0\' for the final cursor position. Insert variable values with \'${varName}\' and \'${varName:defaultText}\', e.g \'This is file: $TM_FILENAME\'.'), type: ['string', 'array'], items: { type: 'string' diff --git a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts index 76256dcaed..0391626e0a 100644 --- a/src/vs/workbench/contrib/snippets/browser/snippetsService.ts +++ b/src/vs/workbench/contrib/snippets/browser/snippetsService.ts @@ -5,7 +5,7 @@ import { join } from 'vs/base/common/path'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { combinedDisposable, dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { combinedDisposable, dispose, IDisposable } from 'vs/base/common/lifecycle'; import { values } from 'vs/base/common/map'; import * as resources from 'vs/base/common/resources'; import { endsWith, isFalsyOrWhitespace } from 'vs/base/common/strings'; @@ -114,7 +114,7 @@ namespace snippetExt { } function watch(service: IFileService, resource: URI, callback: (type: FileChangeType, resource: URI) => any): IDisposable { - return combinedDisposable( + return combinedDisposable([ service.watch(resource), service.onFileChanges(e => { for (const change of e.changes) { @@ -123,7 +123,7 @@ function watch(service: IFileService, resource: URI, callback: (type: FileChange } } }) - ); + ]); } class SnippetsService implements ISnippetsService { @@ -295,16 +295,15 @@ class SnippetsService implements ISnippetsService { } private _initFolderSnippets(source: SnippetSource, folder: URI, bucket: IDisposable[]): Promise { - const disposables = new DisposableStore(); - const addFolderSnippets = (type?: FileChangeType) => { - disposables.clear(); - + let disposables: IDisposable[] = []; + let addFolderSnippets = (type?: FileChangeType) => { + disposables = dispose(disposables); if (type === FileChangeType.DELETED) { return Promise.resolve(); } return this._fileService.resolve(folder).then(stat => { for (const entry of stat.children || []) { - disposables.add(this._addSnippetFile(entry.resource, source)); + disposables.push(this._addSnippetFile(entry.resource, source)); } }, err => { this._logService.error(`Failed snippets from folder '${folder.toString()}'`, err); @@ -312,7 +311,7 @@ class SnippetsService implements ISnippetsService { }; bucket.push(watch(this._fileService, folder, addFolderSnippets)); - bucket.push(disposables); + bucket.push(combinedDisposable(disposables)); return addFolderSnippets(); } diff --git a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts index b621a31d4a..b894e27e7a 100644 --- a/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts +++ b/src/vs/workbench/contrib/splash/electron-browser/partsSplash.contribution.ts @@ -3,13 +3,13 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ipcRenderer as ipc } from 'electron'; import { join } from 'vs/base/common/path'; import { onDidChangeFullscreen, isFullscreen } from 'vs/base/browser/browser'; import { getTotalHeight, getTotalWidth } from 'vs/base/browser/dom'; import { Color } from 'vs/base/common/color'; import { Event } from 'vs/base/common/event'; import { dispose, IDisposable } from 'vs/base/common/lifecycle'; +import { IBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { Registry } from 'vs/platform/registry/common/platform'; import { ColorIdentifier, editorBackground, foreground } from 'vs/platform/theme/common/colorRegistry'; @@ -23,8 +23,6 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { URI } from 'vs/base/common/uri'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IWindowService } from 'vs/platform/windows/common/windows'; -import * as perf from 'vs/base/common/performance'; class PartsSplash { @@ -41,25 +39,19 @@ class PartsSplash { @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService, @ITextFileService private readonly _textFileService: ITextFileService, @IEnvironmentService private readonly _envService: IEnvironmentService, - @IWindowService private readonly windowService: IWindowService, + @IBroadcastService private readonly _broadcastService: IBroadcastService, @ILifecycleService lifecycleService: ILifecycleService, @IEditorGroupsService editorGroupsService: IEditorGroupsService, @IConfigurationService configService: IConfigurationService, ) { - lifecycleService.when(LifecyclePhase.Restored).then(_ => { - this._removePartsSplash(); - perf.mark('didRemovePartsSplash'); - }); + lifecycleService.when(LifecyclePhase.Restored).then(_ => this._removePartsSplash()); Event.debounce(Event.any( onDidChangeFullscreen, editorGroupsService.onDidLayout ), () => { }, 800)(this._savePartsSplash, this, this._disposables); configService.onDidChangeConfiguration(e => { - if (e.affectsConfiguration('window.titleBarStyle')) { - this._didChangeTitleBarStyle = true; - this._savePartsSplash(); - } + this._didChangeTitleBarStyle = e.affectsConfiguration('window.titleBarStyle'); }, this, this._disposables); } @@ -104,8 +96,7 @@ class PartsSplash { // the color needs to be in hex const backgroundColor = this._themeService.getTheme().getColor(editorBackground) || themes.WORKBENCH_BACKGROUND(this._themeService.getTheme()); - const payload = JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }); - ipc.send('vscode:changeColorTheme', this.windowService.windowId, payload); + this._broadcastService.broadcast({ channel: 'vscode:changeColorTheme', payload: JSON.stringify({ baseTheme, background: Color.Format.CSS.formatHex(backgroundColor) }) }); } } diff --git a/src/vs/workbench/contrib/stats/node/workspaceStats.ts b/src/vs/workbench/contrib/stats/node/workspaceStats.ts index 2c8f13120c..6aa96cb9c9 100644 --- a/src/vs/workbench/contrib/stats/node/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/node/workspaceStats.ts @@ -458,7 +458,7 @@ export class WorkspaceStats implements IWorkbenchContribution { if (PyModulesToLookFor.indexOf(packageName) > -1) { tags['workspace.py.' + packageName] = true; } - // cognitive services has a lot of tiny packages. e.g. 'azure-cognitiveservices-search-autosuggest' + // cognitive services has a lot of tiny packages. eg. 'azure-cognitiveservices-search-autosuggest' if (packageName.indexOf('azure-cognitiveservices') > -1) { tags['workspace.py.azure-cognitiveservices'] = true; } diff --git a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts index 00dd2a53da..0b7d44d819 100644 --- a/src/vs/workbench/contrib/tasks/browser/quickOpen.ts +++ b/src/vs/workbench/contrib/tasks/browser/quickOpen.ts @@ -214,7 +214,7 @@ export class QuickOpenActionContributor extends ActionBarContributor { return !!task; } - public getActions(context: any): ReadonlyArray { + public getActions(context: any): IAction[] { let actions: Action[] = []; let task = this.getTask(context); if (task && ContributedTask.is(task) || CustomTask.is(task)) { diff --git a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts index 83f3d00b27..36aba9f059 100644 --- a/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts +++ b/src/vs/workbench/contrib/tasks/common/jsonSchema_v2.ts @@ -50,7 +50,7 @@ const taskIdentifier: IJSONSchema = { properties: { type: { type: 'string', - description: nls.localize('JsonSchema.tasks.dependsOn.identifier', 'The task identifier.') + description: nls.localize('JsonSchema.tasks.dependsOn.identifier', 'The task indentifier.') } } }; @@ -77,17 +77,6 @@ const dependsOn: IJSONSchema = { ] }; -const dependsOrder: IJSONSchema = { - type: 'string', - enum: ['parallel', 'sequence'], - enumDescriptions: [ - nls.localize('JsonSchema.tasks.dependsOrder.parallel', 'Run all dependsOn tasks in parallel.'), - nls.localize('JsonSchema.tasks.dependsOrder.sequence', 'Run all dependsOn tasks in sequence.'), - ], - default: 'parallel', - description: nls.localize('JsonSchema.tasks.dependsOrder', 'Determines the order of the dependsOn tasks for this task. Note that this property is not recursive.') -}; - const presentation: IJSONSchema = { type: 'object', default: { @@ -364,7 +353,6 @@ let taskConfiguration: IJSONSchema = { }, runOptions: Objects.deepClone(runOptions), dependsOn: Objects.deepClone(dependsOn), - dependsOrder: Objects.deepClone(dependsOrder) } }; @@ -417,7 +405,6 @@ taskDescriptionProperties.command = Objects.deepClone(command); taskDescriptionProperties.args = Objects.deepClone(args); taskDescriptionProperties.isShellCommand = Objects.deepClone(shellCommand); taskDescriptionProperties.dependsOn = dependsOn; -taskDescriptionProperties.dependsOrder = dependsOrder; taskDescriptionProperties.identifier = Objects.deepClone(identifier); taskDescriptionProperties.type = Objects.deepClone(taskType); taskDescriptionProperties.presentation = Objects.deepClone(presentation); @@ -435,7 +422,7 @@ taskDescription.default = { problemMatcher: [] }; definitions.showOutputType.deprecationMessage = nls.localize( - 'JsonSchema.tasks.showOutput.deprecated', + 'JsonSchema.tasks.showOputput.deprecated', 'The property showOutput is deprecated. Use the reveal property inside the presentation property instead. See also the 1.14 release notes.' ); taskDescriptionProperties.echoCommand.deprecationMessage = nls.localize( diff --git a/src/vs/workbench/contrib/tasks/common/media/status-error.svg b/src/vs/workbench/contrib/tasks/common/media/status-error.svg new file mode 100644 index 0000000000..61b16362cb --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/status-error.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/tasks/common/media/status-info.svg b/src/vs/workbench/contrib/tasks/common/media/status-info.svg new file mode 100644 index 0000000000..16306356ba --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/status-info.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/tasks/common/media/status-warning.svg b/src/vs/workbench/contrib/tasks/common/media/status-warning.svg new file mode 100644 index 0000000000..5951d69539 --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/status-warning.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css index fcf2ad0ee6..5ffde87453 100644 --- a/src/vs/workbench/contrib/tasks/common/media/task.contribution.css +++ b/src/vs/workbench/contrib/tasks/common/media/task.contribution.css @@ -3,6 +3,80 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +.task-statusbar-runningItem { + display: inline-block; +} + +.task-statusbar-runningItem-label { + display: inline-block; + cursor: pointer; + padding: 0 5px 0 5px; +} + +.task-statusbar-runningItem-label > .octicon { + font-size: 11px; + vertical-align: -webkit-baseline-middle; + height: 19px; +} + +.task-statusbar-item { + display: inline-block; +} + +.task-statusbar-item-icon { + background: url('task.svg') 50% 2px no-repeat; + background-size: 18px; + cursor: pointer; + height: 22px; + width: 24px; + vertical-align: top; +} + +.task-statusbar-item-building { + height: 18px; + padding: 0px 2px 0px 2px; + display: inline-block; + text-align: center; + vertical-align: top; +} + +.task-statusbar-item-label { + display: inline-block; + cursor: pointer; + padding: 0 5px 0 5px; +} + +.task-statusbar-item-label > .task-statusbar-item-label-counter { + display: inline-block; + vertical-align: top; + padding-left: 2px; + padding-right: 2px; +} + +.task-statusbar-item-label > .task-statusbar-item-label-error, +.task-statusbar-item-label > .task-statusbar-item-label-warning, +.task-statusbar-item-label > .task-statusbar-item-label-info { + display: inline-block; + padding-right: 8px; + width: 8px; + height: 22px; +} + +.task-statusbar-item-label > .task-statusbar-item-label-error { + -webkit-mask: url('status-error.svg') no-repeat 50% 50%; + -webkit-mask-size: 11px; +} + +.task-statusbar-item-label > .task-statusbar-item-label-warning { + -webkit-mask: url('status-warning.svg') no-repeat 50% 50%; + -webkit-mask-size: 11px; +} + +.task-statusbar-item-label > .task-statusbar-item-label-info { + -webkit-mask: url('status-info.svg') no-repeat 50% 50%; + -webkit-mask-size: 11px; +} + .monaco-workbench .quick-open-task-configure { background-image: url('configure.svg'); } diff --git a/src/vs/workbench/contrib/tasks/common/media/task.svg b/src/vs/workbench/contrib/tasks/common/media/task.svg new file mode 100644 index 0000000000..7692f495b3 --- /dev/null +++ b/src/vs/workbench/contrib/tasks/common/media/task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts index d396a79dbc..729eb45c02 100644 --- a/src/vs/workbench/contrib/tasks/common/problemCollectors.ts +++ b/src/vs/workbench/contrib/tasks/common/problemCollectors.ts @@ -13,7 +13,6 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import { ILineMatcher, createLineMatcher, ProblemMatcher, ProblemMatch, ApplyToKind, WatchingPattern, getResource } from 'vs/workbench/contrib/tasks/common/problemMatcher'; import { IMarkerService, IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { generateUuid } from 'vs/base/common/uuid'; -import { IFileService } from 'vs/platform/files/common/files'; export const enum ProblemCollectorEventKind { BackgroundProcessingBegins = 'backgroundProcessingBegins', @@ -34,7 +33,7 @@ export interface IProblemMatcher { processLine(line: string): void; } -export abstract class AbstractProblemCollector implements IDisposable { +export class AbstractProblemCollector implements IDisposable { private matchers: INumberDictionary; private activeMatcher: ILineMatcher | null; @@ -44,9 +43,8 @@ export abstract class AbstractProblemCollector implements IDisposable { private bufferLength: number; private openModels: IStringDictionary; private modelListeners: IDisposable[]; - private tail: Promise; - // [owner] -> ApplyToKind + // [owner] -> AppyToKind private applyToByOwner: Map; // [owner] -> [resource] -> URI private resourcesToClean: Map>; @@ -57,10 +55,10 @@ export abstract class AbstractProblemCollector implements IDisposable { protected _onDidStateChange: Emitter; - constructor(problemMatchers: ProblemMatcher[], protected markerService: IMarkerService, private modelService: IModelService, fileService?: IFileService) { + constructor(problemMatchers: ProblemMatcher[], protected markerService: IMarkerService, private modelService: IModelService) { this.matchers = Object.create(null); this.bufferLength = 1; - problemMatchers.map(elem => createLineMatcher(elem, fileService)).forEach((matcher) => { + problemMatchers.map(elem => createLineMatcher(elem)).forEach((matcher) => { let length = matcher.matchLength; if (length > this.bufferLength) { this.bufferLength = length; @@ -105,19 +103,6 @@ export abstract class AbstractProblemCollector implements IDisposable { return this._onDidStateChange.event; } - public processLine(line: string) { - if (this.tail) { - const oldTail = this.tail; - this.tail = oldTail.then(() => { - return this.processLineInternal(line); - }); - } else { - this.tail = this.processLineInternal(line); - } - } - - protected abstract async processLineInternal(line: string): Promise; - public dispose() { this.modelListeners.forEach(disposable => disposable.dispose()); } @@ -158,14 +143,14 @@ export abstract class AbstractProblemCollector implements IDisposable { return result; } - protected async shouldApplyMatch(result: ProblemMatch): Promise { + protected shouldApplyMatch(result: ProblemMatch): boolean { switch (result.description.applyTo) { case ApplyToKind.allDocuments: return true; case ApplyToKind.openDocuments: - return !!this.openModels[(await result.resource).toString()]; + return !!this.openModels[result.resource.toString()]; case ApplyToKind.closedDocuments: - return !this.openModels[(await result.resource).toString()]; + return !this.openModels[result.resource.toString()]; default: return true; } @@ -287,9 +272,9 @@ export abstract class AbstractProblemCollector implements IDisposable { protected reportMarkers(): void { this.markers.forEach((markersPerOwner, owner) => { - let deliveredMarkersPerOwner = this.getDeliveredMarkersPerOwner(owner); + let develieredMarkersPerOwner = this.getDeliveredMarkersPerOwner(owner); markersPerOwner.forEach((markers, resource) => { - this.deliverMarkersPerOwnerAndResourceResolved(owner, resource, markers, deliveredMarkersPerOwner); + this.deliverMarkersPerOwnerAndResourceResolved(owner, resource, markers, develieredMarkersPerOwner); }); }); } @@ -348,8 +333,8 @@ export class StartStopProblemCollector extends AbstractProblemCollector implemen private currentOwner: string; private currentResource: string; - constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean, fileService?: IFileService) { - super(problemMatchers, markerService, modelService, fileService); + constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, _strategy: ProblemHandlingStrategy = ProblemHandlingStrategy.Clean) { + super(problemMatchers, markerService, modelService); let ownerSet: { [key: string]: boolean; } = Object.create(null); problemMatchers.forEach(description => ownerSet[description.owner] = true); this.owners = Object.keys(ownerSet); @@ -358,17 +343,17 @@ export class StartStopProblemCollector extends AbstractProblemCollector implemen }); } - protected async processLineInternal(line: string): Promise { + public processLine(line: string): void { let markerMatch = this.tryFindMarker(line); if (!markerMatch) { return; } let owner = markerMatch.description.owner; - let resource = await markerMatch.resource; + let resource = markerMatch.resource; let resourceAsString = resource.toString(); this.removeResourceToClean(owner, resourceAsString); - let shouldApplyMatch = await this.shouldApplyMatch(markerMatch); + let shouldApplyMatch = this.shouldApplyMatch(markerMatch); if (shouldApplyMatch) { this.recordMarker(markerMatch.marker, owner, resourceAsString); if (this.currentOwner !== owner || this.currentResource !== resourceAsString) { @@ -401,8 +386,8 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement private currentOwner: string | null; private currentResource: string | null; - constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService, fileService?: IFileService) { - super(problemMatchers, markerService, modelService, fileService); + constructor(problemMatchers: ProblemMatcher[], markerService: IMarkerService, modelService: IModelService) { + super(problemMatchers, markerService, modelService); this.problemMatchers = problemMatchers; this.resetCurrentResource(); this.backgroundPatterns = []; @@ -430,19 +415,19 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement } } - protected async processLineInternal(line: string): Promise { - if (await this.tryBegin(line) || this.tryFinish(line)) { + public processLine(line: string): void { + if (this.tryBegin(line) || this.tryFinish(line)) { return; } let markerMatch = this.tryFindMarker(line); if (!markerMatch) { return; } - let resource = await markerMatch.resource; + let resource = markerMatch.resource; let owner = markerMatch.description.owner; let resourceAsString = resource.toString(); this.removeResourceToClean(owner, resourceAsString); - let shouldApplyMatch = await this.shouldApplyMatch(markerMatch); + let shouldApplyMatch = this.shouldApplyMatch(markerMatch); if (shouldApplyMatch) { this.recordMarker(markerMatch.marker, owner, resourceAsString); if (this.currentOwner !== owner || this.currentResource !== resourceAsString) { @@ -457,7 +442,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement this.reportMarkersForCurrentResource(); } - private async tryBegin(line: string): Promise { + private tryBegin(line: string): boolean { let result = false; for (const background of this.backgroundPatterns) { let matches = background.begin.regexp.exec(line); @@ -474,7 +459,7 @@ export class WatchingProblemCollector extends AbstractProblemCollector implement let file = matches[background.begin.file!]; if (file) { let resource = getResource(file, background.matcher); - this.recordResourceToClean(owner, await resource); + this.recordResourceToClean(owner, resource); } else { this.recordResourcesToClean(owner); } diff --git a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts index 939895074e..a52b738698 100644 --- a/src/vs/workbench/contrib/tasks/common/problemMatcher.ts +++ b/src/vs/workbench/contrib/tasks/common/problemMatcher.ts @@ -21,13 +21,11 @@ import { IStringDictionary } from 'vs/base/common/collections'; import { IMarkerData, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { ExtensionsRegistry, ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { Event, Emitter } from 'vs/base/common/event'; -import { IFileService, IFileStat } from 'vs/platform/files/common/files'; export enum FileLocationKind { - Default, + Auto, Relative, - Absolute, - AutoDetect + Absolute } export module FileLocationKind { @@ -37,8 +35,6 @@ export module FileLocationKind { return FileLocationKind.Absolute; } else if (value === 'relative') { return FileLocationKind.Relative; - } else if (value === 'autodetect') { - return FileLocationKind.AutoDetect; } else { return undefined; } @@ -176,7 +172,7 @@ interface ProblemData { } export interface ProblemMatch { - resource: Promise; + resource: URI; marker: IMarkerData; description: ProblemMatcher; } @@ -186,32 +182,13 @@ export interface HandleResult { continue: boolean; } - -export async function getResource(filename: string, matcher: ProblemMatcher, fileService?: IFileService): Promise { +export function getResource(filename: string, matcher: ProblemMatcher): URI { let kind = matcher.fileLocation; let fullPath: string | undefined; if (kind === FileLocationKind.Absolute) { fullPath = filename; } else if ((kind === FileLocationKind.Relative) && matcher.filePrefix) { fullPath = join(matcher.filePrefix, filename); - } else if (kind === FileLocationKind.AutoDetect) { - const matcherClone = Objects.deepClone(matcher); - matcherClone.fileLocation = FileLocationKind.Relative; - if (fileService) { - const relative = await getResource(filename, matcherClone); - let stat: IFileStat | undefined = undefined; - try { - stat = await fileService.resolve(relative); - } catch (ex) { - // Do nothing, we just need to catch file resolution errors. - } - if (stat) { - return relative; - } - } - - matcherClone.fileLocation = FileLocationKind.Absolute; - return getResource(filename, matcherClone); } if (fullPath === undefined) { throw new Error('FileLocationKind is not actionable. Does the matcher have a filePrefix? This should never happen.'); @@ -233,12 +210,12 @@ export interface ILineMatcher { handle(lines: string[], start?: number): HandleResult; } -export function createLineMatcher(matcher: ProblemMatcher, fileService?: IFileService): ILineMatcher { +export function createLineMatcher(matcher: ProblemMatcher): ILineMatcher { let pattern = matcher.pattern; if (Types.isArray(pattern)) { - return new MultiLineMatcher(matcher, fileService); + return new MultiLineMatcher(matcher); } else { - return new SingleLineMatcher(matcher, fileService); + return new SingleLineMatcher(matcher); } } @@ -246,11 +223,9 @@ const endOfLine: string = Platform.OS === Platform.OperatingSystem.Windows ? '\r abstract class AbstractLineMatcher implements ILineMatcher { private matcher: ProblemMatcher; - private fileService?: IFileService; - constructor(matcher: ProblemMatcher, fileService?: IFileService) { + constructor(matcher: ProblemMatcher) { this.matcher = matcher; - this.fileService = fileService; } public handle(lines: string[], start: number = 0): HandleResult { @@ -337,8 +312,8 @@ abstract class AbstractLineMatcher implements ILineMatcher { return undefined; } - protected getResource(filename: string): Promise { - return getResource(filename, this.matcher, this.fileService); + protected getResource(filename: string): URI { + return getResource(filename, this.matcher); } private getLocation(data: ProblemData): Location | null { @@ -414,8 +389,8 @@ class SingleLineMatcher extends AbstractLineMatcher { private pattern: ProblemPattern; - constructor(matcher: ProblemMatcher, fileService?: IFileService) { - super(matcher, fileService); + constructor(matcher: ProblemMatcher) { + super(matcher); this.pattern = matcher.pattern; } @@ -450,8 +425,8 @@ class MultiLineMatcher extends AbstractLineMatcher { private patterns: ProblemPattern[]; private data: ProblemData | null; - constructor(matcher: ProblemMatcher, fileService?: IFileService) { - super(matcher, fileService); + constructor(matcher: ProblemMatcher) { + super(matcher); this.patterns = matcher.pattern; } @@ -1370,7 +1345,7 @@ export class ProblemMatcherParser extends Parser { kind = FileLocationKind.fromString(description.fileLocation); if (kind) { fileLocation = kind; - if ((kind === FileLocationKind.Relative) || (kind === FileLocationKind.AutoDetect)) { + if (kind === FileLocationKind.Relative) { filePrefix = '${workspaceFolder}'; } } @@ -1380,7 +1355,7 @@ export class ProblemMatcherParser extends Parser { kind = FileLocationKind.fromString(values[0]); if (values.length === 1 && kind === FileLocationKind.Absolute) { fileLocation = kind; - } else if (values.length === 2 && (kind === FileLocationKind.Relative || kind === FileLocationKind.AutoDetect) && values[1]) { + } else if (values.length === 2 && kind === FileLocationKind.Relative && values[1]) { fileLocation = kind; filePrefix = values[1]; } @@ -1598,7 +1573,7 @@ export namespace Schemas { oneOf: [ { type: 'string', - enum: ['absolute', 'relative', 'autoDetect'] + enum: ['absolute', 'relative'] }, { type: 'array', diff --git a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts index 96abed3450..2ccc9984f8 100644 --- a/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts +++ b/src/vs/workbench/contrib/tasks/common/taskConfiguration.ts @@ -312,11 +312,6 @@ export interface ConfigurationProperties { */ dependsOn?: string | TaskIdentifier | Array; - /** - * The order the dependsOn tasks should be executed in. - */ - dependsOrder?: string; - /** * Controls the behavior of the used terminal */ @@ -1084,7 +1079,7 @@ namespace CommandConfiguration { value.args = EMPTY_ARRAY; } if (value.suppressTaskName === undefined) { - value.suppressTaskName = (context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0); + value.suppressTaskName = false; } } @@ -1219,18 +1214,6 @@ namespace TaskDependency { } } -namespace DependsOrder { - export function from(order: string | undefined): Tasks.DependsOrder { - switch (order) { - case Tasks.DependsOrder.sequence: - return Tasks.DependsOrder.sequence; - case Tasks.DependsOrder.parallel: - default: - return Tasks.DependsOrder.parallel; - } - } -} - namespace ConfigurationProperties { const properties: MetaData[] = [ @@ -1286,7 +1269,6 @@ namespace ConfigurationProperties { result.dependsOn = dependsOnValue ? [dependsOnValue] : undefined; } } - result.dependsOrder = DependsOrder.from(external.dependsOrder); if (includeCommandOptions && (external.presentation !== undefined || (external as LegacyCommandProperties).terminal !== undefined)) { result.presentation = CommandConfiguration.PresentationOptions.from(external, context); } @@ -1407,6 +1389,7 @@ namespace ConfiguringTask { } namespace CustomTask { + export function from(this: void, external: CustomTask, context: ParseContext, index: number): Tasks.CustomTask | undefined { if (!external) { return undefined; @@ -1728,7 +1711,7 @@ namespace Globals { } CommandConfiguration.fillDefaults(value.command, context); if (value.suppressTaskName === undefined) { - value.suppressTaskName = (context.schemaVersion === Tasks.JsonSchemaVersion.V2_0_0); + value.suppressTaskName = false; } if (value.promptOnClose === undefined) { value.promptOnClose = true; diff --git a/src/vs/workbench/contrib/tasks/common/taskSystem.ts b/src/vs/workbench/contrib/tasks/common/taskSystem.ts index 2f3b12bf39..a5ebe23548 100644 --- a/src/vs/workbench/contrib/tasks/common/taskSystem.ts +++ b/src/vs/workbench/contrib/tasks/common/taskSystem.ts @@ -121,7 +121,7 @@ export interface TaskSystemInfo { resolveVariables(workspaceFolder: IWorkspaceFolder, toResolve: ResolveSet): Promise; } -export interface TaskSystemInfoResolver { +export interface TaskSystemInfoResovler { (workspaceFolder: IWorkspaceFolder): TaskSystemInfo | undefined; } diff --git a/src/vs/workbench/contrib/tasks/common/tasks.ts b/src/vs/workbench/contrib/tasks/common/tasks.ts index 607bc0f107..8eb48222aa 100644 --- a/src/vs/workbench/contrib/tasks/common/tasks.ts +++ b/src/vs/workbench/contrib/tasks/common/tasks.ts @@ -431,11 +431,6 @@ export const enum GroupType { user = 'user' } -export const enum DependsOrder { - parallel = 'parallel', - sequence = 'sequence' -} - export interface ConfigurationProperties { /** @@ -483,11 +478,6 @@ export interface ConfigurationProperties { */ dependsOn?: TaskDependency[]; - /** - * The order the dependsOn tasks should be executed in. - */ - dependsOrder?: DependsOrder; - /** * The problem watchers to use for this task */ @@ -617,7 +607,7 @@ export class CustomTask extends CommonTask { type: '$customized'; // CUSTOMIZED_TASK_TYPE /** - * Indicated the source of the task (e.g. tasks.json or extension) + * Indicated the source of the task (e.g tasks.json or extension) */ _source: WorkspaceTaskSource; @@ -724,7 +714,7 @@ export class CustomTask extends CommonTask { export class ConfiguringTask extends CommonTask { /** - * Indicated the source of the task (e.g. tasks.json or extension) + * Indicated the source of the task (e.g tasks.json or extension) */ _source: WorkspaceTaskSource; @@ -750,7 +740,7 @@ export class ConfiguringTask extends CommonTask { export class ContributedTask extends CommonTask { /** - * Indicated the source of the task (e.g. tasks.json or extension) + * Indicated the source of the task (e.g tasks.json or extension) */ _source: ExtensionTaskSource; @@ -817,7 +807,7 @@ export class ContributedTask extends CommonTask { export class InMemoryTask extends CommonTask { /** - * Indicated the source of the task (e.g. tasks.json or extension) + * Indicated the source of the task (e.g tasks.json or extension) */ _source: InMemoryTaskSource; diff --git a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts index b499f3e41c..7622c16e6f 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/task.contribution.ts @@ -14,7 +14,8 @@ import * as Objects from 'vs/base/common/objects'; import { URI } from 'vs/base/common/uri'; import { IStringDictionary } from 'vs/base/common/collections'; import { Action } from 'vs/base/common/actions'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import * as Dom from 'vs/base/browser/dom'; +import { IDisposable, dispose, toDisposable, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter } from 'vs/base/common/event'; import * as Types from 'vs/base/common/types'; import { KeyMod, KeyCode } from 'vs/base/common/keyCodes'; @@ -24,12 +25,13 @@ import { ValidationStatus, ValidationState } from 'vs/base/common/parsers'; import * as UUID from 'vs/base/common/uuid'; import * as Platform from 'vs/base/common/platform'; import { LinkedMap, Touch } from 'vs/base/common/map'; +import { OcticonLabel } from 'vs/base/browser/ui/octiconLabel/octiconLabel'; import { Registry } from 'vs/platform/registry/common/platform'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { MenuRegistry, MenuId, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IMarkerService } from 'vs/platform/markers/common/markers'; +import { IMarkerService, MarkerStatistics } from 'vs/platform/markers/common/markers'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; import { IFileService, IFileStat } from 'vs/platform/files/common/files'; @@ -38,7 +40,7 @@ import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { ProblemMatcherRegistry, NamedProblemMatcher } from 'vs/workbench/contrib/tasks/common/problemMatcher'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; -import { IProgressService, IProgressOptions, ProgressLocation } from 'vs/platform/progress/common/progress'; +import { IProgressService2, IProgressOptions, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -50,7 +52,8 @@ import { IModelService } from 'vs/editor/common/services/modelService'; import * as jsonContributionRegistry from 'vs/platform/jsonschemas/common/jsonContributionRegistry'; import { IJSONSchema } from 'vs/base/common/jsonSchema'; -import { StatusbarAlignment, IStatusbarService, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/platform/statusbar/common/statusbar'; +import { IStatusbarItem, IStatusbarRegistry, Extensions as StatusbarExtensions, StatusbarItemDescriptor } from 'vs/workbench/browser/parts/statusbar/statusbar'; +import { StatusbarAlignment } from 'vs/platform/statusbar/common/statusbar'; import { IQuickOpenRegistry, Extensions as QuickOpenExtensions, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; @@ -82,11 +85,13 @@ import { TerminalTaskSystem } from './terminalTaskSystem'; import { ProcessRunnerDetector } from 'vs/workbench/contrib/tasks/node/processRunnerDetector'; import { QuickOpenActionContributor } from '../browser/quickOpen'; +import { Themable, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_FOREGROUND } from 'vs/workbench/common/theme'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IQuickInputService, IQuickPickItem, QuickPickInput } from 'vs/platform/quickinput/common/quickInput'; import { TaskDefinitionRegistry } from 'vs/workbench/contrib/tasks/common/taskDefinitionRegistry'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; -import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry, IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { Extensions as WorkbenchExtensions, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { RunAutomaticTasks, AllowAutomaticTaskRunning, DisallowAutomaticTaskRunning } from 'vs/workbench/contrib/tasks/electron-browser/runAutomaticTasks'; @@ -101,118 +106,247 @@ const actionRegistry = Registry.as(ActionExtensions.Wo actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(AllowAutomaticTaskRunning, AllowAutomaticTaskRunning.ID, AllowAutomaticTaskRunning.LABEL), 'Tasks: Allow Automatic Tasks in Folder', tasksCategory); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(DisallowAutomaticTaskRunning, DisallowAutomaticTaskRunning.ID, DisallowAutomaticTaskRunning.LABEL), 'Tasks: Disallow Automatic Tasks in Folder', tasksCategory); + namespace ConfigureTaskAction { export const ID = 'workbench.action.tasks.configureTaskRunner'; export const TEXT = nls.localize('ConfigureTaskRunnerAction.label', "Configure Task"); } -export class TaskStatusBarContributions extends Disposable implements IWorkbenchContribution { - private runningTasksStatusItem: IStatusbarEntryAccessor | undefined; - private activeTasksCount: number = 0; +class BuildStatusBarItem extends Themable implements IStatusbarItem { + private activeCount: number; + private icons: HTMLElement[]; constructor( + @IPanelService private readonly panelService: IPanelService, + @IMarkerService private readonly markerService: IMarkerService, @ITaskService private readonly taskService: ITaskService, - @IStatusbarService private readonly statusbarService: IStatusbarService, - @IProgressService private readonly progressService: IProgressService + @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IThemeService themeService: IThemeService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService ) { - super(); + super(themeService); + + this.activeCount = 0; + this.icons = []; + this.registerListeners(); } private registerListeners(): void { - let promise: Promise | undefined = undefined; - let resolver: (value?: void | Thenable) => void; - this.taskService.onDidStateChange(event => { - if (event.kind === TaskEventKind.Changed) { - this.updateRunningTasksStatus(); - } + this._register(this.contextService.onDidChangeWorkbenchState(() => this.updateStyles())); + } - if (!this.ignoreEventForUpdateRunningTasksCount(event)) { - switch (event.kind) { - case TaskEventKind.Active: - this.activeTasksCount++; - if (this.activeTasksCount === 1) { - if (!promise) { - promise = new Promise((resolve) => { - resolver = resolve; - }); - } - } - break; - case TaskEventKind.Inactive: - // Since the exiting of the sub process is communicated async we can't order inactive and terminate events. - // So try to treat them accordingly. - if (this.activeTasksCount > 0) { - this.activeTasksCount--; - if (this.activeTasksCount === 0) { - if (promise && resolver!) { - resolver!(); - } - } - } - break; - case TaskEventKind.Terminated: - if (this.activeTasksCount !== 0) { - this.activeTasksCount = 0; - if (promise && resolver!) { - resolver!(); - } - } - break; - } - } + protected updateStyles(): void { + super.updateStyles(); - if (promise && (event.kind === TaskEventKind.Active) && (this.activeTasksCount === 1)) { - this.progressService.withProgress({ location: ProgressLocation.Window }, progress => { - progress.report({ message: nls.localize('building', 'Building...') }); - return promise!; - }).then(() => { - promise = undefined; - }); - } + this.icons.forEach(icon => { + icon.style.backgroundColor = this.getColor(this.contextService.getWorkbenchState() !== WorkbenchState.EMPTY ? STATUS_BAR_FOREGROUND : STATUS_BAR_NO_FOLDER_FOREGROUND); }); } - private async updateRunningTasksStatus(): Promise { - const tasks = await this.taskService.getActiveTasks(); - if (tasks.length === 0) { - if (this.runningTasksStatusItem) { - this.runningTasksStatusItem.dispose(); - this.runningTasksStatusItem = undefined; - } - } else { - const itemProps: IStatusbarEntry = { - text: `$(tools) ${tasks.length}`, - tooltip: nls.localize('runningTasks', "Show Running Tasks"), - command: 'workbench.action.tasks.showTasks', - }; + public render(container: HTMLElement): IDisposable { + let callOnDispose: IDisposable[] = []; - if (!this.runningTasksStatusItem) { - this.runningTasksStatusItem = this.statusbarService.addEntry(itemProps, 'status.runningTasks', nls.localize('status.runningTasks', "Running Tasks"), StatusbarAlignment.LEFT, 50 /* Medium Priority */); + const element = document.createElement('div'); + const label = document.createElement('a'); + const errorIcon = document.createElement('div'); + const warningIcon = document.createElement('div'); + const infoIcon = document.createElement('div'); + const error = document.createElement('div'); + const warning = document.createElement('div'); + const info = document.createElement('div'); + const building = document.createElement('div'); + + const errorTitle = (n: number) => nls.localize('totalErrors', "{0} Errors", n); + const warningTitle = (n: number) => nls.localize('totalWarnings', "{0} Warnings", n); + const infoTitle = (n: number) => nls.localize('totalInfos', "{0} Infos", n); + + Dom.addClass(element, 'task-statusbar-item'); + element.title = nls.localize('problems', "Problems"); + + Dom.addClass(label, 'task-statusbar-item-label'); + element.appendChild(label); + + Dom.addClass(errorIcon, 'task-statusbar-item-label-error'); + Dom.addClass(errorIcon, 'mask-icon'); + label.appendChild(errorIcon); + this.icons.push(errorIcon); + + Dom.addClass(error, 'task-statusbar-item-label-counter'); + error.innerHTML = '0'; + error.title = errorIcon.title = errorTitle(0); + label.appendChild(error); + + Dom.addClass(warningIcon, 'task-statusbar-item-label-warning'); + Dom.addClass(warningIcon, 'mask-icon'); + label.appendChild(warningIcon); + this.icons.push(warningIcon); + + Dom.addClass(warning, 'task-statusbar-item-label-counter'); + warning.innerHTML = '0'; + warning.title = warningIcon.title = warningTitle(0); + label.appendChild(warning); + + Dom.addClass(infoIcon, 'task-statusbar-item-label-info'); + Dom.addClass(infoIcon, 'mask-icon'); + label.appendChild(infoIcon); + this.icons.push(infoIcon); + Dom.hide(infoIcon); + + Dom.addClass(info, 'task-statusbar-item-label-counter'); + label.appendChild(info); + Dom.hide(info); + + Dom.addClass(building, 'task-statusbar-item-building'); + element.appendChild(building); + building.innerHTML = nls.localize('building', 'Building...'); + Dom.hide(building); + + callOnDispose.push(Dom.addDisposableListener(label, 'click', (e: MouseEvent) => { + const panel = this.panelService.getActivePanel(); + if (panel && panel.getId() === Constants.MARKERS_PANEL_ID) { + this.layoutService.setPanelHidden(true); } else { - this.runningTasksStatusItem.update(itemProps); + this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true); } - } + })); + + const manyProblems = nls.localize('manyProblems', "10K+"); + const packNumber = (n: number) => n > 9999 ? manyProblems : n > 999 ? n.toString().charAt(0) + 'K' : n.toString(); + let updateLabel = (stats: MarkerStatistics) => { + error.innerHTML = packNumber(stats.errors); + error.title = errorIcon.title = errorTitle(stats.errors); + warning.innerHTML = packNumber(stats.warnings); + warning.title = warningIcon.title = warningTitle(stats.warnings); + if (stats.infos > 0) { + info.innerHTML = packNumber(stats.infos); + info.title = infoIcon.title = infoTitle(stats.infos); + Dom.show(info); + Dom.show(infoIcon); + } else { + Dom.hide(info); + Dom.hide(infoIcon); + } + }; + + this.markerService.onMarkerChanged((changedResources) => { + updateLabel(this.markerService.getStatistics()); + }); + + callOnDispose.push(this.taskService.onDidStateChange((event) => { + if (this.ignoreEvent(event)) { + return; + } + switch (event.kind) { + case TaskEventKind.Active: + this.activeCount++; + if (this.activeCount === 1) { + Dom.show(building); + } + break; + case TaskEventKind.Inactive: + // Since the exiting of the sub process is communicated async we can't order inactive and terminate events. + // So try to treat them accordingly. + if (this.activeCount > 0) { + this.activeCount--; + if (this.activeCount === 0) { + Dom.hide(building); + } + } + break; + case TaskEventKind.Terminated: + if (this.activeCount !== 0) { + Dom.hide(building); + this.activeCount = 0; + } + break; + } + })); + + container.appendChild(element); + + this.updateStyles(); + + return toDisposable(() => { + callOnDispose = dispose(callOnDispose); + }); } - private ignoreEventForUpdateRunningTasksCount(event: TaskEvent): boolean { + private ignoreEvent(event: TaskEvent): boolean { if (!this.taskService.inTerminal()) { return false; } - if (event.group !== TaskGroup.Build) { return true; } - if (!event.__task) { return false; } - return event.__task.configurationProperties.problemMatchers === undefined || event.__task.configurationProperties.problemMatchers.length === 0; } } -workbenchRegistry.registerWorkbenchContribution(TaskStatusBarContributions, LifecyclePhase.Restored); +class TaskStatusBarItem extends Themable implements IStatusbarItem { + + constructor( + @ITaskService private readonly taskService: ITaskService, + @IThemeService themeService: IThemeService, + ) { + super(themeService); + } + + protected updateStyles(): void { + super.updateStyles(); + } + + public render(container: HTMLElement): IDisposable { + + let callOnDispose: IDisposable[] = []; + const element = document.createElement('a'); + Dom.addClass(element, 'task-statusbar-runningItem'); + + let labelElement = document.createElement('div'); + Dom.addClass(labelElement, 'task-statusbar-runningItem-label'); + element.appendChild(labelElement); + + let label = new OcticonLabel(labelElement); + label.title = nls.localize('runningTasks', "Show Running Tasks"); + + Dom.hide(element); + + callOnDispose.push(Dom.addDisposableListener(labelElement, 'click', (e: MouseEvent) => { + (this.taskService as TaskService).runShowTasks(); + })); + + let updateStatus = (): void => { + this.taskService.getActiveTasks().then(tasks => { + if (tasks.length === 0) { + Dom.hide(element); + } else { + label.text = `$(tools) ${tasks.length}`; + Dom.show(element); + } + }); + }; + + callOnDispose.push(this.taskService.onDidStateChange((event) => { + if (event.kind === TaskEventKind.Changed) { + updateStatus(); + } + })); + + container.appendChild(element); + + this.updateStyles(); + updateStatus(); + + return { + dispose: () => { + callOnDispose = dispose(callOnDispose); + } + }; + } +} class ProblemReporter implements TaskConfig.IProblemReporter { @@ -348,14 +482,13 @@ class TaskService extends Disposable implements ITaskService { @IConfigurationResolverService private readonly configurationResolverService: IConfigurationResolverService, @ITerminalService private readonly terminalService: ITerminalService, @IStorageService private readonly storageService: IStorageService, - @IProgressService private readonly progressService: IProgressService, + @IProgressService2 private readonly progressService: IProgressService2, @IOpenerService private readonly openerService: IOpenerService, @IWindowService private readonly _windowService: IWindowService, @IDialogService private readonly dialogService: IDialogService, @INotificationService private readonly notificationService: INotificationService, @IContextKeyService contextKeyService: IContextKeyService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService ) { super(); @@ -490,15 +623,6 @@ class TaskService extends Disposable implements ITaskService { CommandsRegistry.registerCommand('workbench.action.tasks.showTasks', () => { this.runShowTasks(); }); - - CommandsRegistry.registerCommand('workbench.action.tasks.toggleProblems', () => { - const panel = this.panelService.getActivePanel(); - if (panel && panel.getId() === Constants.MARKERS_PANEL_ID) { - this.layoutService.setPanelHidden(true); - } else { - this.panelService.openPanel(Constants.MARKERS_PANEL_ID, true); - } - }); } private get workspaceFolders(): IWorkspaceFolder[] { @@ -1234,8 +1358,8 @@ class TaskService extends Disposable implements ITaskService { this._taskSystem = new TerminalTaskSystem( this.terminalService, this.outputService, this.panelService, this.markerService, this.modelService, this.configurationResolverService, this.telemetryService, - this.contextService, this.environmentService, - TaskService.OutputChannelId, this.fileService, + this.contextService, this._environmentService, + TaskService.OutputChannelId, (workspaceFolder: IWorkspaceFolder) => { if (!workspaceFolder) { return undefined; @@ -2586,6 +2710,11 @@ quickOpenRegistry.registerQuickOpenHandler( const actionBarRegistry = Registry.as(ActionBarExtensions.Actionbar); actionBarRegistry.registerActionBarContributor(Scope.VIEWER, QuickOpenActionContributor); +// Status bar +let statusbarRegistry = Registry.as(StatusbarExtensions.Statusbar); +statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(BuildStatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */)); +statusbarRegistry.registerStatusbarItem(new StatusbarItemDescriptor(TaskStatusBarItem, StatusbarAlignment.LEFT, 50 /* Medium Priority */)); + // tasks.json validation let schemaId = 'vscode://schemas/tasks'; let schema: IJSONSchema = { diff --git a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts index c94d0fe6fa..9d10fe2681 100644 --- a/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/electron-browser/terminalTaskSystem.ts @@ -17,7 +17,7 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isUNC } from 'vs/base/common/extpath'; import { win32 } from 'vs/base/node/processes'; -import { IFileService } from 'vs/platform/files/common/files'; + import { IMarkerService, MarkerSeverity } from 'vs/platform/markers/common/markers'; import { IWorkspaceContextService, WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -29,14 +29,14 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import { ITerminalService, ITerminalInstance, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { IOutputService } from 'vs/workbench/contrib/output/common/output'; -import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEventKind, ProblemHandlingStrategy } from 'vs/workbench/contrib/tasks/common/problemCollectors'; +import { StartStopProblemCollector, WatchingProblemCollector, ProblemCollectorEventKind } from 'vs/workbench/contrib/tasks/common/problemCollectors'; import { Task, CustomTask, ContributedTask, RevealKind, CommandOptions, ShellConfiguration, RuntimeType, PanelKind, - TaskEvent, TaskEventKind, ShellQuotingOptions, ShellQuoting, CommandString, CommandConfiguration, ExtensionTaskSource, TaskScope, RevealProblemKind, DependsOrder + TaskEvent, TaskEventKind, ShellQuotingOptions, ShellQuoting, CommandString, CommandConfiguration, ExtensionTaskSource, TaskScope, RevealProblemKind } from 'vs/workbench/contrib/tasks/common/tasks'; import { ITaskSystem, ITaskSummary, ITaskExecuteResult, TaskExecuteKind, TaskError, TaskErrors, ITaskResolver, - TelemetryEvent, Triggers, TaskTerminateResponse, TaskSystemInfoResolver, TaskSystemInfo, ResolveSet, ResolvedVariables + TelemetryEvent, Triggers, TaskTerminateResponse, TaskSystemInfoResovler, TaskSystemInfo, ResolveSet, ResolvedVariables } from 'vs/workbench/contrib/tasks/common/taskSystem'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { URI } from 'vs/base/common/uri'; @@ -154,7 +154,7 @@ export class TerminalTaskSystem implements ITaskSystem { private terminals: IStringDictionary; private idleTaskTerminals: LinkedMap; private sameTaskTerminals: IStringDictionary; - private taskSystemInfoResolver: TaskSystemInfoResolver; + private taskSystemInfoResolver: TaskSystemInfoResovler; private lastTask: VerifiedTask; private currentTask: VerifiedTask; private isRerun: boolean; @@ -171,8 +171,7 @@ export class TerminalTaskSystem implements ITaskSystem { private contextService: IWorkspaceContextService, private environmentService: IWorkbenchEnvironmentService, private outputChannelId: string, - private fileService: IFileService, - taskSystemInfoResolver: TaskSystemInfoResolver, + taskSystemInfoResolver: TaskSystemInfoResovler, ) { this.activeTasks = Object.create(null); @@ -333,11 +332,10 @@ export class TerminalTaskSystem implements ITaskSystem { return Promise.all(promises); } - private async executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise { + private executeTask(task: Task, resolver: ITaskResolver, trigger: string): Promise { let promises: Promise[] = []; if (task.configurationProperties.dependsOn) { - for (let index in task.configurationProperties.dependsOn) { - const dependency = task.configurationProperties.dependsOn[index]; + task.configurationProperties.dependsOn.forEach((dependency) => { let dependencyTask = resolver.resolve(dependency.workspaceFolder, dependency.task!); if (dependencyTask) { let key = dependencyTask.getMapKey(); @@ -346,9 +344,6 @@ export class TerminalTaskSystem implements ITaskSystem { this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.DependsOnStarted, task)); promise = this.executeTask(dependencyTask, resolver, trigger); } - if (task.configurationProperties.dependsOrder === DependsOrder.sequence) { - promise = Promise.resolve(await promise); - } promises.push(promise); } else { this.log(nls.localize('dependencyFailed', @@ -358,7 +353,7 @@ export class TerminalTaskSystem implements ITaskSystem { )); this.showOutput(); } - } + }); } if ((ContributedTask.is(task) || CustomTask.is(task)) && (task.command)) { @@ -429,12 +424,12 @@ export class TerminalTaskSystem implements ITaskSystem { variables.forEach(variable => variablesArray.push(variable)); return new Promise((resolve, reject) => { - this.configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks').then(async resolvedVariablesMap => { + this.configurationResolverService.resolveWithInteraction(workspaceFolder, variablesArray, 'tasks').then(resolvedVariablesMap => { if (resolvedVariablesMap) { if (isProcess) { let processVarValue: string; if (Platform.isWindows) { - processVarValue = await win32.findExecutable( + processVarValue = win32.findExecutable( this.configurationResolverService.resolve(workspaceFolder, CommandString.value(task.command.name!)), cwd ? this.configurationResolverService.resolve(workspaceFolder, cwd) : undefined, envPath ? envPath.split(path.delimiter).map(p => this.configurationResolverService.resolve(workspaceFolder, p)) : undefined @@ -514,7 +509,7 @@ export class TerminalTaskSystem implements ITaskSystem { if (task.configurationProperties.isBackground) { promise = new Promise((resolve, reject) => { const problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); - let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService, this.fileService); + let watchingProblemMatcher = new WatchingProblemCollector(problemMatchers, this.markerService, this.modelService); let toDispose: IDisposable[] | undefined = []; let eventCounter: number = 0; toDispose.push(watchingProblemMatcher.onDidStateChange((event) => { @@ -635,7 +630,7 @@ export class TerminalTaskSystem implements ITaskSystem { this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Start, task, terminal.id)); this._onDidStateChange.fire(TaskEvent.create(TaskEventKind.Active, task)); let problemMatchers = this.resolveMatchers(resolver, task.configurationProperties.problemMatchers); - let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService, ProblemHandlingStrategy.Clean, this.fileService); + let startStopProblemMatcher = new StartStopProblemCollector(problemMatchers, this.markerService, this.modelService); const registeredLinkMatchers = this.registerLinkMatchers(terminal, problemMatchers); const onData = terminal.onLineData((line) => { startStopProblemMatcher.processLine(line); @@ -1235,7 +1230,7 @@ export class TerminalTaskSystem implements ITaskSystem { matcher = value; } if (!matcher) { - this.appendOutput(nls.localize('unknownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored')); + this.appendOutput(nls.localize('unkownProblemMatcher', 'Problem matcher {0} can\'t be resolved. The matcher will be ignored')); return; } let taskSystemInfo: TaskSystemInfo | undefined = resolver.taskSystemInfo; diff --git a/src/vs/workbench/contrib/terminal/browser/media/xterm.css b/src/vs/workbench/contrib/terminal/browser/media/xterm.css index e09e08d08a..361924fdbd 100644 --- a/src/vs/workbench/contrib/terminal/browser/media/xterm.css +++ b/src/vs/workbench/contrib/terminal/browser/media/xterm.css @@ -128,7 +128,7 @@ } .xterm.enable-mouse-events { - /* When mouse events are enabled (e.g. tmux), revert to the standard pointer cursor */ + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ cursor: default; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index 1fd01ace06..e3a75356f3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -260,10 +260,15 @@ configurationRegistry.registerConfiguration({ default: 'inherited' }, 'terminal.integrated.windowsEnableConpty': { - description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication (requires Windows 10 build number 18309+). Winpty will be used if this is false."), + description: nls.localize('terminal.integrated.windowsEnableConpty', "Whether to use ConPTY for Windows terminal process communication. Winpty will be used if this is false. Note that ConPTY will be disabled regardless of this setting when the Windows 10 build number is lower than 18309 or when you're running the 32-bit VS Code client under 64-bit Windows."), type: 'boolean', default: true }, + 'terminal.integrated.enableLatencyMitigation': { + description: nls.localize('terminal.integrated.enableLatencyMitigation', "Whether to enable the latency mitigation feature for high-latency terminals."), + type: 'boolean', + default: false + }, 'terminal.integrated.experimentalRefreshOnResume': { description: nls.localize('terminal.integrated.experimentalRefreshOnResume', "An experimental setting that will refresh the terminal renderer when the system is resumed."), type: 'boolean', @@ -392,7 +397,8 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(MoveToLineEndTer mac: { primary: KeyMod.CtrlCmd | KeyCode.RightArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Move To Line End', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SplitTerminalAction, SplitTerminalAction.ID, SplitTerminalAction.LABEL, { - primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5, + primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, + secondary: [KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.KEY_5], mac: { primary: KeyMod.CtrlCmd | KeyCode.US_BACKSLASH, secondary: [KeyMod.WinCtrl | KeyMod.Shift | KeyCode.KEY_5] diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.ts b/src/vs/workbench/contrib/terminal/browser/terminal.ts index 34c76d2ea6..dd4b778bc3 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.ts @@ -3,10 +3,8 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Terminal as XTermTerminal } from 'xterm'; -import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links'; -import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; -import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; +import { Terminal as XTermTerminal } from 'vscode-xterm'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalProcessManager, ITerminalConfigHelper, ITerminalChildProcess, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; @@ -16,9 +14,8 @@ export interface ITerminalInstanceService { _serviceBrand: any; getXtermConstructor(): Promise; - getXtermWebLinksConstructor(): Promise; - getXtermSearchConstructor(): Promise; createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper; + createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager; createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess; getDefaultShell(p: Platform): string; } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index 7fea9ff674..c114669abc 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -748,10 +748,10 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { ) { super(null, action, terminalService.getTabLabels().map(label => { text: label }), terminalService.activeTabIndex, contextViewService, { ariaLabel: nls.localize('terminals', 'Open Terminals.') }); - this._register(terminalService.onInstancesChanged(this._updateItems, this)); - this._register(terminalService.onActiveTabChanged(this._updateItems, this)); - this._register(terminalService.onInstanceTitleChanged(this._updateItems, this)); - this._register(attachSelectBoxStyler(this.selectBox, themeService)); + this.toDispose.push(terminalService.onInstancesChanged(this._updateItems, this)); + this.toDispose.push(terminalService.onActiveTabChanged(this._updateItems, this)); + this.toDispose.push(terminalService.onInstanceTitleChanged(this._updateItems, this)); + this.toDispose.push(attachSelectBoxStyler(this.selectBox, themeService)); } private _updateItems(): void { @@ -1041,7 +1041,7 @@ export class QuickOpenActionTermContributor extends ActionBarContributor { super(); } - public getActions(context: any): ReadonlyArray { + public getActions(context: any): IAction[] { const actions: Action[] = []; if (context.element instanceof TerminalEntry) { actions.push(this.instantiationService.createInstance(RenameTerminalQuickOpenAction, RenameTerminalQuickOpenAction.ID, RenameTerminalQuickOpenAction.LABEL, context.element)); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts b/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts index a9b29119ad..145e54e243 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalCommandTracker.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Terminal, IMarker } from 'xterm'; +import { Terminal, IMarker } from 'vscode-xterm'; import { ITerminalCommandTracker } from 'vs/workbench/contrib/terminal/common/terminal'; import { IDisposable } from 'vs/base/common/lifecycle'; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts index e80dea6307..8e99da0d64 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalConfigHelper.ts @@ -10,7 +10,7 @@ import { IConfigurationService } from 'vs/platform/configuration/common/configur import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ITerminalConfiguration, ITerminalFont, IShellLaunchConfig, IS_WORKSPACE_SHELL_ALLOWED_STORAGE_KEY, TERMINAL_CONFIG_SECTION, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, MINIMUM_LETTER_SPACING, LinuxDistro } from 'vs/workbench/contrib/terminal/common/terminal'; import Severity from 'vs/base/common/severity'; -import { Terminal as XTermTerminal } from 'xterm'; +import { Terminal as XTermTerminal } from 'vscode-xterm'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { IBrowserTerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminal'; import { mergeDefaultShellPathAndArgs } from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index 4e8db284f9..b403ebba10 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -32,17 +32,16 @@ import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/term import { TerminalLinkHandler } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { ISearchOptions, Terminal as XTermTerminal, IBuffer } from 'vscode-xterm'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; -import { Terminal as XTermTerminal, IBuffer } from 'xterm'; -import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer const SLOW_CANVAS_RENDER_THRESHOLD = 50; const NUMBER_OF_FRAMES_TO_MEASURE = 20; + export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TERMINAL_COMMAND_ID.CLEAR_SELECTION, TERMINAL_COMMAND_ID.CLEAR, @@ -149,8 +148,6 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ 'workbench.action.toggleMaximizedPanel' ]; -let xtermConstructor: Promise | undefined; - export class TerminalInstance implements ITerminalInstance { private static readonly EOL_REGEX = /\r?\n/g; @@ -169,7 +166,6 @@ export class TerminalInstance implements ITerminalInstance { private _title: string; private _wrapperElement: HTMLDivElement; private _xterm: XTermTerminal; - private _xtermSearch: SearchAddon | undefined; private _xtermElement: HTMLDivElement; private _terminalHasTextContextKey: IContextKey; private _cols: number; @@ -395,26 +391,11 @@ export class TerminalInstance implements ITerminalInstance { return TerminalInstance._lastKnownDimensions; } - private async _getXtermConstructor(): Promise { - if (xtermConstructor) { - return xtermConstructor; - } - xtermConstructor = new Promise(async (resolve) => { - const Terminal = await this._terminalInstanceService.getXtermConstructor(); - // Localize strings - Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line'); - Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); - Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read'); - resolve(Terminal); - }); - return xtermConstructor; - } - /** * Create xterm.js instance and attach data listeners. */ protected async _createXterm(): Promise { - const Terminal = await this._getXtermConstructor(); + const Terminal = await this._terminalInstanceService.getXtermConstructor(); const font = this._configHelper.getFont(undefined, true); const config = this._configHelper.config; this._xterm = new Terminal({ @@ -433,11 +414,9 @@ export class TerminalInstance implements ITerminalInstance { macOptionClickForcesSelection: config.macOptionClickForcesSelection, rightClickSelectsWord: config.rightClickBehavior === 'selectWord', // TODO: Guess whether to use canvas or dom better - rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType - }); - this._terminalInstanceService.getXtermSearchConstructor().then(Addon => { - this._xtermSearch = new Addon(); - this._xterm.loadAddon(this._xtermSearch); + rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType, + // TODO: Remove this once the setting is removed upstream + experimentalCharAtlas: 'dynamic' }); if (this._shellLaunchConfig.initialText) { this._xterm.writeln(this._shellLaunchConfig.initialText); @@ -616,6 +595,19 @@ export class TerminalInstance implements ITerminalInstance { if (this._processManager) { this._widgetManager = new TerminalWidgetManager(this._wrapperElement); this._processManager.onProcessReady(() => this._linkHandler.setWidgetManager(this._widgetManager)); + + this._processManager.onProcessReady(() => { + if (this._configHelper.config.enableLatencyMitigation) { + if (!this._processManager) { + return; + } + this._processManager.getLatency().then(latency => { + if (latency > 20 && (this._xterm as any).typeAheadInit) { + (this._xterm as any).typeAheadInit(this._processManager, this._themeService); + } + }); + } + }); } else if (this._shellLaunchConfig.isRendererOnly) { this._widgetManager = new TerminalWidgetManager(this._wrapperElement); this._linkHandler.setWidgetManager(this._widgetManager); @@ -722,17 +714,11 @@ export class TerminalInstance implements ITerminalInstance { } public findNext(term: string, searchOptions: ISearchOptions): boolean { - if (!this._xtermSearch) { - return false; - } - return this._xtermSearch.findNext(term, searchOptions); + return this._xterm.findNext(term, searchOptions); } public findPrevious(term: string, searchOptions: ISearchOptions): boolean { - if (!this._xtermSearch) { - return false; - } - return this._xtermSearch.findPrevious(term, searchOptions); + return this._xterm.findPrevious(term, searchOptions); } public notifyFindWidgetFocusChanged(isFocused: boolean): void { @@ -789,7 +775,7 @@ export class TerminalInstance implements ITerminalInstance { public rendererExit(exitCode: number): void { // The use of this API is for cases where there is no backing process behind a terminal - // instance (e.g. a custom execution task). + // instance (eg. a custom execution task). if (!this.shellLaunchConfig.isRendererOnly) { throw new Error('rendererExit is only expected to be called on a renderer only terminal'); } @@ -929,7 +915,7 @@ export class TerminalInstance implements ITerminalInstance { } protected _createProcess(): void { - this._processManager = this._instantiationService.createInstance(TerminalProcessManager, this._id, this._configHelper); + this._processManager = this._terminalInstanceService.createTerminalProcessManager(this._id, this._configHelper); this._processManager.onProcessReady(() => this._onProcessIdReady.fire(this)); this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode)); this._processManager.onProcessData(data => this._onData.fire(data)); @@ -973,7 +959,7 @@ export class TerminalInstance implements ITerminalInstance { /** * Called when either a process tied to a terminal has exited or when a terminal renderer - * simulates a process exiting (e.g. custom execution task). + * simulates a process exiting (eg. custom execution task). * @param exitCode The exit code of the process, this is undefined when the terminal was exited * through user action. */ @@ -1137,17 +1123,9 @@ export class TerminalInstance implements ITerminalInstance { } private _sendLineData(buffer: IBuffer, lineIndex: number): void { - let line = buffer.getLine(lineIndex); - if (!line) { - return; - } - let lineData = line.translateToString(true); - while (lineIndex > 0 && line.isWrapped) { - line = buffer.getLine(--lineIndex); - if (!line) { - break; - } - lineData = line.translateToString(false) + lineData; + let lineData = buffer.getLine(lineIndex)!.translateToString(true); + while (lineIndex >= 0 && buffer.getLine(lineIndex--)!.isWrapped) { + lineData = buffer.getLine(lineIndex)!.translateToString(false) + lineData; } this._onLineData.fire(lineData); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts index 51852cd461..ad4dcd43fd 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalLinkHandler.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import * as platform from 'vs/base/common/platform'; import { URI } from 'vs/base/common/uri'; -import { dispose, IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { IOpenerService } from 'vs/platform/opener/common/opener'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -14,10 +14,9 @@ import { ITerminalService, ITerminalProcessManager } from 'vs/workbench/contrib/ import { ITextEditorSelection } from 'vs/platform/editor/common/editor'; import { IEditorService } from 'vs/workbench/services/editor/common/editorService'; import { IFileService } from 'vs/platform/files/common/files'; -import { ILinkMatcherOptions } from 'xterm'; +import { ILinkMatcherOptions } from 'vscode-xterm'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { posix, win32 } from 'vs/base/common/path'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; const pathPrefix = '(\\.\\.?|\\~)'; const pathSeparatorClause = '\\/'; @@ -65,14 +64,13 @@ interface IPath { } export class TerminalLinkHandler { - private readonly _hoverDisposables = new DisposableStore(); + private _hoverDisposables: IDisposable[] = []; private _mouseMoveDisposable: IDisposable; private _widgetManager: TerminalWidgetManager; private _processCwd: string; private _gitDiffPreImagePattern: RegExp; private _gitDiffPostImagePattern: RegExp; private readonly _tooltipCallback: (event: MouseEvent, uri: string) => boolean | void; - private readonly _leaveCallback: () => void; constructor( private _xterm: any, @@ -82,7 +80,6 @@ export class TerminalLinkHandler { @IEditorService private readonly _editorService: IEditorService, @IConfigurationService private readonly _configurationService: IConfigurationService, @ITerminalService private readonly _terminalService: ITerminalService, - @ITerminalInstanceService private readonly _terminalInstanceService: ITerminalInstanceService, @IFileService private readonly _fileService: IFileService ) { // Matches '--- a/src/file1', capturing 'src/file1' in group 1 @@ -101,11 +98,6 @@ export class TerminalLinkHandler { this._widgetManager.showMessage(e.offsetX, e.offsetY, this._getLinkHoverString()); } }; - this._leaveCallback = () => { - if (this._widgetManager) { - this._widgetManager.closeMessage(); - } - }; this.registerWebLinkHandler(); if (this._platform) { @@ -126,7 +118,11 @@ export class TerminalLinkHandler { const options: ILinkMatcherOptions = { matchIndex, tooltipCallback: this._tooltipCallback, - leaveCallback: this._leaveCallback, + leaveCallback: () => { + if (this._widgetManager) { + this._widgetManager.closeMessage(); + } + }, willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e), priority: CUSTOM_LINK_PRIORITY }; @@ -137,16 +133,18 @@ export class TerminalLinkHandler { } public registerWebLinkHandler(): void { - this._terminalInstanceService.getXtermWebLinksConstructor().then((WebLinksAddon) => { - const wrappedHandler = this._wrapLinkHandler(uri => { - this._handleHypertextLink(uri); - }); - this._xterm.loadAddon(new WebLinksAddon(wrappedHandler, { - validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateWebLink(uri, callback), - tooltipCallback: this._tooltipCallback, - leaveCallback: this._leaveCallback, - willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e) - })); + const wrappedHandler = this._wrapLinkHandler(uri => { + this._handleHypertextLink(uri); + }); + this._xterm.webLinksInit(wrappedHandler, { + validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateWebLink(uri, callback), + tooltipCallback: this._tooltipCallback, + leaveCallback: () => { + if (this._widgetManager) { + this._widgetManager.closeMessage(); + } + }, + willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e) }); } @@ -157,7 +155,11 @@ export class TerminalLinkHandler { this._xterm.registerLinkMatcher(this._localLinkRegex, wrappedHandler, { validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback), tooltipCallback: this._tooltipCallback, - leaveCallback: this._leaveCallback, + leaveCallback: () => { + if (this._widgetManager) { + this._widgetManager.closeMessage(); + } + }, willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e), priority: LOCAL_LINK_PRIORITY }); @@ -171,7 +173,11 @@ export class TerminalLinkHandler { matchIndex: 1, validationCallback: (uri: string, callback: (isValid: boolean) => void) => this._validateLocalLink(uri, callback), tooltipCallback: this._tooltipCallback, - leaveCallback: this._leaveCallback, + leaveCallback: () => { + if (this._widgetManager) { + this._widgetManager.closeMessage(); + } + }, willLinkActivate: (e: MouseEvent) => this._isLinkActivationModifierDown(e), priority: LOCAL_LINK_PRIORITY }; @@ -181,8 +187,7 @@ export class TerminalLinkHandler { public dispose(): void { this._xterm = null; - - this._hoverDisposables.dispose(); + this._hoverDisposables = dispose(this._hoverDisposables); this._mouseMoveDisposable = dispose(this._mouseMoveDisposable); } diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index df0f611fc8..647b4e4a58 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -5,6 +5,7 @@ import * as platform from 'vs/base/common/platform'; import * as terminalEnvironment from 'vs/workbench/contrib/terminal/common/terminalEnvironment'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { ProcessState, ITerminalProcessManager, IShellLaunchConfig, ITerminalConfigHelper, ITerminalChildProcess, IBeforeProcessDataEvent, ITerminalEnvironment } from 'vs/workbench/contrib/terminal/common/terminal'; import { ILogService } from 'vs/platform/log/common/log'; import { Emitter, Event } from 'vs/base/common/event'; @@ -47,6 +48,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { private _process: ITerminalChildProcess | null = null; private _preLaunchInputQueue: string[] = []; + private _disposables: IDisposable[] = []; private _latency: number = -1; private _latencyRequest: Promise; private _latencyLastMeasured: number = 0; @@ -94,6 +96,12 @@ export class TerminalProcessManager implements ITerminalProcessManager { this._process.shutdown(immediate); this._process = null; } + this._disposables.forEach(d => d.dispose()); + this._disposables.length = 0; + } + + public addDisposable(disposable: IDisposable) { + this._disposables.push(disposable); } public createProcess( diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index 611bf6fc94..201fed9470 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -50,16 +50,6 @@ export abstract class TerminalService extends CommonTerminalService implements I } public createTerminal(shell: IShellLaunchConfig = {}): ITerminalInstance { - if (shell.runInBackground) { - const instance = this.createInstance(this._terminalFocusContextKey, - this.configHelper, - undefined, - shell, - true); - this._backgroundedTerminalInstances.push(instance); - this._initInstanceListeners(instance); - return instance; - } const terminalTab = this._instantiationService.createInstance(TerminalTab, this._terminalFocusContextKey, this.configHelper, @@ -78,24 +68,6 @@ export abstract class TerminalService extends CommonTerminalService implements I return instance; } - protected _showBackgroundTerminal(instance: ITerminalInstance): void { - this._backgroundedTerminalInstances.splice(this._backgroundedTerminalInstances.indexOf(instance), 1); - instance.shellLaunchConfig.runInBackground = false; - const terminalTab = this._instantiationService.createInstance(TerminalTab, - this._terminalFocusContextKey, - this.configHelper, - this._terminalContainer, - instance); - this._terminalTabs.push(terminalTab); - terminalTab.addDisposable(terminalTab.onDisposed(this._onTabDisposed.fire, this._onTabDisposed)); - terminalTab.addDisposable(terminalTab.onInstancesChanged(this._onInstancesChanged.fire, this._onInstancesChanged)); - if (this.terminalInstances.length === 1) { - // It's the first instance so it should be made active automatically - this.setActiveInstanceByIndex(0); - } - this._onInstancesChanged.fire(); - } - public focusFindWidget(): Promise { return this.showPanel(false).then(() => { const panel = this._panelService.getActivePanel() as TerminalPanel; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 4962be96b5..a0a064985c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -225,7 +225,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, private _container: HTMLElement, - shellLaunchConfigOrInstance: IShellLaunchConfig | ITerminalInstance, + shellLaunchConfig: IShellLaunchConfig, @ITerminalService private readonly _terminalService: ITerminalService, @IWorkbenchLayoutService private readonly _layoutService: IWorkbenchLayoutService ) { @@ -233,17 +233,12 @@ export class TerminalTab extends Disposable implements ITerminalTab { this._onDisposed = new Emitter(); this._onInstancesChanged = new Emitter(); - let instance: ITerminalInstance; - if ('id' in shellLaunchConfigOrInstance) { - instance = shellLaunchConfigOrInstance; - } else { - instance = this._terminalService.createInstance( - terminalFocusContextKey, - configHelper, - undefined, - shellLaunchConfigOrInstance, - true); - } + const instance = this._terminalService.createInstance( + terminalFocusContextKey, + configHelper, + undefined, + shellLaunchConfig, + true); this._terminalInstances.push(instance); this._initInstanceListeners(instance); this._activeInstanceIndex = 0; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts new file mode 100644 index 0000000000..95f9c387fc --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon.ts @@ -0,0 +1,136 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Terminal as XTermTerminal } from 'vscode-xterm'; +import { ITerminalProcessManager } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; + +export interface ITerminalCore { + buffer: any; +} + +export interface ITypeAheadAddonTerminal { + _core: ITerminalCore; + on: any; + write(data: string): void; + cols: number; + + __typeAheadQueue: string[]; + __typeAheadState: TypeAheadState; + __typeAheadCurrentYBase: number; + __typeAheadCurrentY: number; +} + +enum TypeAheadState { + /** + * The normal state, ready to type if it starts. + */ + Normal, + /** + * Something happens such that we cannot make a good guess on what to print, + * wait until the cursor row changes before proceeding. + */ + AwaitingRowChange +} + +function isCharPrintable(data: string): boolean { + const code = data.charCodeAt(0); + return data.length === 1 && code >= 32 && code <= 126; +} + +function init(terminal: any, processManager: ITerminalProcessManager, themeService: IThemeService): void { + const t = terminal as ITypeAheadAddonTerminal; + + t.__typeAheadQueue = []; + t.__typeAheadState = TypeAheadState.Normal; + t.__typeAheadCurrentYBase = 0; + t.__typeAheadCurrentY = 0; + + function typeAhead(data: string): void { + for (let i = 0; i < data.length; i++) { + t.__typeAheadQueue.push(data[i]); + } + t.write(data); + } + + t.on('cursormove', () => { + // Reset if the cursor row changed + if (t._core.buffer.ybase !== t.__typeAheadCurrentYBase || t._core.buffer.y !== t.__typeAheadCurrentY) { + t.__typeAheadCurrentYBase = t._core.buffer.ybase; + t.__typeAheadCurrentY = t._core.buffer.y; + t.__typeAheadState = TypeAheadState.Normal; + } + }); + + t.on('data', (data: string) => { + // Exit if we're waiting for a row change + if (t.__typeAheadState === TypeAheadState.AwaitingRowChange) { + return; + } + + // Only enable in the normal buffer + if (!t._core.buffer._hasScrollback) { + return; + } + + // // Handle enter + // if (data === '\r') { + // typeAhead('\r\n'); + // return; + // } + + // // Left arrow + // if (data === '\x1b[D') { + // // TODO: How to stop it from going beyond prompt? + // typeAhead(String.fromCharCode(8)); + // } + + // // Right arrow + // if (data === '\x1b[C') { + // // TODO: How to stop it from going beyond prompt? + // typeAhead('\x1b[C'); + // } + + // // Backspace (DEL) + // if (data.charCodeAt(0) === 127) { + // // TODO: This would require knowing the prompt length to be able to shift everything + // } + + if (!isCharPrintable(data)) { + t.__typeAheadState = TypeAheadState.AwaitingRowChange; + return; + } + + if (t._core.buffer.x === t.cols - 1) { + // TODO: Does the space get added on Windows/Linux too? + data += ' \r'; + } + typeAhead(data); + }); + + processManager.onBeforeProcessData(event => { + let consumeCount = 0; + for (let i = 0; i < event.data.length; i++) { + if (t.__typeAheadQueue[0] === event.data[i]) { + t.__typeAheadQueue.shift(); + consumeCount++; + } else { + t.__typeAheadQueue.length = 0; + break; + } + } + if (consumeCount === event.data.length) { + event.data = ''; + } else if (consumeCount > 0) { + event.data = event.data.substr(consumeCount); + } + }); +} + +export function apply(terminalConstructor: typeof XTermTerminal) { + (terminalConstructor.prototype).typeAheadInit = function (processManager: ITerminalProcessManager, themeService: IThemeService): void { + init(this, processManager, themeService); + }; +} diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index 046c59ff82..41eb68db93 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -101,6 +101,7 @@ export interface ITerminalConfiguration { experimentalBufferImpl: 'JsArray' | 'TypedArray'; splitCwd: 'workspaceRoot' | 'initial' | 'inherited'; windowsEnableConpty: boolean; + enableLatencyMitigation: boolean; experimentalRefreshOnResume: boolean; } @@ -161,7 +162,7 @@ export interface IShellLaunchConfig { env?: ITerminalEnvironment; /** - * Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (e.g. if the + * Whether to ignore a custom cwd from the `terminal.integrated.cwd` settings key (eg. if the * shell is being launched by an extension). */ ignoreConfigurationCwd?: boolean; @@ -191,15 +192,6 @@ export interface IShellLaunchConfig { * provided as nothing will be inherited from the process or any configuration. */ strictEnv?: boolean; - - /** - * When enabled the terminal will run the process as normal but not be surfaced to the user - * until `Terminal.show` is called. The typical usage for this is when you need to run - * something that may need interactivity but only want to tell the user about it when - * interaction is needed. Note that the terminals will still be exposed to all extensions - * as normal. - */ - runInBackground?: boolean; } export interface ITerminalService { @@ -434,7 +426,7 @@ export interface ITerminalInstance { /** * Whether to disable layout for the terminal. This is useful when the size of the terminal is - * being manipulating (e.g. adding a split pane) and we want the terminal to ignore particular + * being manipulating (eg. adding a split pane) and we want the terminal to ignore particular * resize events. */ disableLayout: boolean; @@ -671,6 +663,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly onProcessTitle: Event; readonly onProcessExit: Event; + addDisposable(disposable: IDisposable): void; dispose(immediate?: boolean): void; createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number): void; write(data: string): void; diff --git a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts index 861ae33eb7..9b97977009 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalColorRegistry.ts @@ -37,7 +37,7 @@ export const TERMINAL_BORDER_COLOR = registerColor('terminal.border', { hc: PANEL_BORDER }, nls.localize('terminal.border', 'The color of the border that separates split panes within the terminal. This defaults to panel.border.')); -export const ansiColorMap = { +const ansiColorMap = { 'terminal.ansiBlack': { index: 0, defaults: { diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index 44abad724a..35b2ef7104 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -5,36 +5,37 @@ import { Event, Emitter } from 'vs/base/common/event'; import { ITerminalService, ITerminalProcessExtHostProxy, IShellLaunchConfig, ITerminalChildProcess, ITerminalConfigHelper } from 'vs/workbench/contrib/terminal/common/terminal'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import * as nls from 'vs/nls'; let hasReceivedResponse: boolean = false; -export class TerminalProcessExtHostProxy extends Disposable implements ITerminalChildProcess, ITerminalProcessExtHostProxy { +export class TerminalProcessExtHostProxy implements ITerminalChildProcess, ITerminalProcessExtHostProxy { + private _disposables: IDisposable[] = []; - private readonly _onProcessData = this._register(new Emitter()); - public readonly onProcessData: Event = this._onProcessData.event; - private readonly _onProcessExit = this._register(new Emitter()); - public readonly onProcessExit: Event = this._onProcessExit.event; - private readonly _onProcessIdReady = this._register(new Emitter()); - public readonly onProcessIdReady: Event = this._onProcessIdReady.event; - private readonly _onProcessTitleChanged = this._register(new Emitter()); - public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; + private readonly _onProcessData = new Emitter(); + public get onProcessData(): Event { return this._onProcessData.event; } + private readonly _onProcessExit = new Emitter(); + public get onProcessExit(): Event { return this._onProcessExit.event; } + private readonly _onProcessIdReady = new Emitter(); + public get onProcessIdReady(): Event { return this._onProcessIdReady.event; } + private readonly _onProcessTitleChanged = new Emitter(); + public get onProcessTitleChanged(): Event { return this._onProcessTitleChanged.event; } - private readonly _onInput = this._register(new Emitter()); - public readonly onInput: Event = this._onInput.event; - private readonly _onResize: Emitter<{ cols: number, rows: number }> = this._register(new Emitter<{ cols: number, rows: number }>()); - public readonly onResize: Event<{ cols: number, rows: number }> = this._onResize.event; - private readonly _onShutdown = this._register(new Emitter()); - public readonly onShutdown: Event = this._onShutdown.event; - private readonly _onRequestInitialCwd = this._register(new Emitter()); - public readonly onRequestInitialCwd: Event = this._onRequestInitialCwd.event; - private readonly _onRequestCwd = this._register(new Emitter()); - public readonly onRequestCwd: Event = this._onRequestCwd.event; - private readonly _onRequestLatency = this._register(new Emitter()); - public readonly onRequestLatency: Event = this._onRequestLatency.event; + private readonly _onInput = new Emitter(); + public get onInput(): Event { return this._onInput.event; } + private readonly _onResize: Emitter<{ cols: number, rows: number }> = new Emitter<{ cols: number, rows: number }>(); + public get onResize(): Event<{ cols: number, rows: number }> { return this._onResize.event; } + private readonly _onShutdown = new Emitter(); + public get onShutdown(): Event { return this._onShutdown.event; } + private readonly _onRequestInitialCwd = new Emitter(); + public get onRequestInitialCwd(): Event { return this._onRequestInitialCwd.event; } + private readonly _onRequestCwd = new Emitter(); + public get onRequestCwd(): Event { return this._onRequestCwd.event; } + private readonly _onRequestLatency = new Emitter(); + public get onRequestLatency(): Event { return this._onRequestLatency.event; } private _pendingInitialCwdRequests: ((value?: string | Thenable) => void)[] = []; private _pendingCwdRequests: ((value?: string | Thenable) => void)[] = []; @@ -50,7 +51,6 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal @ITerminalService private readonly _terminalService: ITerminalService, @IRemoteAgentService readonly remoteAgentService: IRemoteAgentService ) { - super(); remoteAgentService.getEnvironment().then(env => { if (!env) { throw new Error('Could not fetch environment'); @@ -62,6 +62,11 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal } } + public dispose(): void { + this._disposables.forEach(d => d.dispose()); + this._disposables.length = 0; + } + public emitData(data: string): void { this._onProcessData.fire(data); } diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index e8620d0459..2d04dff02c 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -30,7 +30,6 @@ export abstract class TerminalService implements ITerminalService { protected _findWidgetVisible: IContextKey; protected _terminalContainer: HTMLElement; protected _terminalTabs: ITerminalTab[] = []; - protected _backgroundedTerminalInstances: ITerminalInstance[] = []; protected get _terminalInstances(): ITerminalInstance[] { return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); } @@ -104,8 +103,8 @@ export abstract class TerminalService implements ITerminalService { protected abstract _getWslPath(path: string): Promise; protected abstract _getWindowsBuildNumber(): number; - protected abstract _showBackgroundTerminal(instance: ITerminalInstance): void; + public abstract refreshActiveTab(): void; public abstract createTerminal(shell?: IShellLaunchConfig, wasNewTerminalAction?: boolean): ITerminalInstance; public abstract createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; public abstract getDefaultShell(platform: Platform): string; @@ -207,11 +206,6 @@ export abstract class TerminalService implements ITerminalService { } } - public refreshActiveTab(): void { - // Fire active instances changed - this._onActiveTabChanged.fire(); - } - public getActiveTab(): ITerminalTab | null { if (this._activeTabIndex < 0 || this._activeTabIndex >= this._terminalTabs.length) { return null; @@ -228,15 +222,6 @@ export abstract class TerminalService implements ITerminalService { } public getInstanceFromId(terminalId: number): ITerminalInstance { - let bgIndex = -1; - this._backgroundedTerminalInstances.forEach((terminalInstance, i) => { - if (terminalInstance.id === terminalId) { - bgIndex = i; - } - }); - if (bgIndex !== -1) { - return this._backgroundedTerminalInstances[bgIndex]; - } return this.terminalInstances[this._getIndexFromId(terminalId)]; } @@ -245,11 +230,6 @@ export abstract class TerminalService implements ITerminalService { } public setActiveInstance(terminalInstance: ITerminalInstance): void { - // If this was a runInBackground terminal created by the API this was triggered by show, - // in which case we need to create the terminal tab - if (terminalInstance.shellLaunchConfig.runInBackground) { - this._showBackgroundTerminal(terminalInstance); - } this.setActiveInstanceByIndex(this._getIndexFromId(terminalInstance.id)); } @@ -461,14 +441,15 @@ export abstract class TerminalService implements ITerminalService { public preparePathForTerminalAsync(originalPath: string, executable: string, title: string): Promise { return new Promise(c => { - if (!executable) { + const exe = executable; + if (!exe) { c(originalPath); return; } const hasSpace = originalPath.indexOf(' ') !== -1; - const pathBasename = basename(executable, '.exe'); + const pathBasename = basename(exe, '.exe'); const isPowerShell = pathBasename === 'pwsh' || title === 'pwsh' || pathBasename === 'powershell' || @@ -482,9 +463,7 @@ export abstract class TerminalService implements ITerminalService { if (isWindows) { // 17063 is the build number where wsl path was introduced. // Update Windows uriPath to be executed in WSL. - const lowerExecutable = executable.toLowerCase(); - if (this._getWindowsBuildNumber() >= 17063 && - (lowerExecutable.indexOf('wsl') !== -1 || (lowerExecutable.indexOf('bash.exe') !== -1 && lowerExecutable.toLowerCase().indexOf('git') === -1))) { + if (((exe.indexOf('wsl') !== -1) || ((exe.indexOf('bash.exe') !== -1) && (exe.indexOf('git') === -1))) && (this._getWindowsBuildNumber() >= 17063)) { c(this._getWslPath(originalPath)); return; } else if (hasSpace) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalShellConfig.ts b/src/vs/workbench/contrib/terminal/common/terminalShellConfig.ts deleted file mode 100644 index fc594ac055..0000000000 --- a/src/vs/workbench/contrib/terminal/common/terminalShellConfig.ts +++ /dev/null @@ -1,45 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; -import { Registry } from 'vs/platform/registry/common/platform'; -import { Platform } from 'vs/base/common/platform'; - -export function registerShellConfiguration(getDefaultShell?: (p: Platform) => string): void { - const configurationRegistry = Registry.as(Extensions.Configuration); - configurationRegistry.registerConfiguration({ - id: 'terminal', - order: 100, - title: nls.localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"), - type: 'object', - properties: { - 'terminal.integrated.shell.linux': { - markdownDescription: - getDefaultShell - ? nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Linux)) - : nls.localize('terminal.integrated.shell.linux.noDefault', "The path of the shell that the terminal uses on Linux. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - type: ['string', 'null'], - default: null - }, - 'terminal.integrated.shell.osx': { - markdownDescription: - getDefaultShell - ? nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Mac)) - : nls.localize('terminal.integrated.shell.osx.noDefault', "The path of the shell that the terminal uses on macOS. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - type: ['string', 'null'], - default: null - }, - 'terminal.integrated.shell.windows': { - markdownDescription: - getDefaultShell - ? nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(Platform.Windows)) - : nls.localize('terminal.integrated.shell.windows.noDefault', "The path of the shell that the terminal uses on Windows. [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration)."), - type: ['string', 'null'], - default: null - } - } - }); -} diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts index fa765e401b..e746c3d018 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminal.contribution.ts @@ -3,14 +3,41 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as platform from 'vs/base/common/platform'; +import * as nls from 'vs/nls'; +import { Extensions, IConfigurationRegistry } from 'vs/platform/configuration/common/configurationRegistry'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { Registry } from 'vs/platform/registry/common/platform'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; import { ITerminalService } from 'vs/workbench/contrib/terminal/common/terminal'; import { TerminalInstanceService } from 'vs/workbench/contrib/terminal/electron-browser/terminalInstanceService'; import { TerminalService } from 'vs/workbench/contrib/terminal/electron-browser/terminalService'; import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; -import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig'; -registerShellConfiguration(getDefaultShell); +const configurationRegistry = Registry.as(Extensions.Configuration); +configurationRegistry.registerConfiguration({ + id: 'terminal', + order: 100, + title: nls.localize('terminalIntegratedConfigurationTitle', "Integrated Terminal"), + type: 'object', + properties: { + 'terminal.integrated.shell.linux': { + markdownDescription: nls.localize('terminal.integrated.shell.linux', "The path of the shell that the terminal uses on Linux (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Linux)), + type: ['string', 'null'], + default: null + }, + 'terminal.integrated.shell.osx': { + markdownDescription: nls.localize('terminal.integrated.shell.osx', "The path of the shell that the terminal uses on macOS (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Mac)), + type: ['string', 'null'], + default: null + }, + 'terminal.integrated.shell.windows': { + markdownDescription: nls.localize('terminal.integrated.shell.windows', "The path of the shell that the terminal uses on Windows (default: {0}). [Read more about configuring the shell](https://code.visualstudio.com/docs/editor/integrated-terminal#_configuration).", getDefaultShell(platform.Platform.Windows)), + type: ['string', 'null'], + default: null + } + } +}); + registerSingleton(ITerminalService, TerminalService, true); registerSingleton(ITerminalInstanceService, TerminalInstanceService, true); diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts index eac1551a76..953aabe361 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalInstanceService.ts @@ -3,20 +3,19 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; -import { ITerminalInstance, IWindowsShellHelper, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; +import { Terminal as XTermTerminal } from 'vscode-xterm'; +import { ITerminalInstance, IWindowsShellHelper, ITerminalConfigHelper, ITerminalProcessManager, IShellLaunchConfig, ITerminalChildProcess } from 'vs/workbench/contrib/terminal/common/terminal'; import { WindowsShellHelper } from 'vs/workbench/contrib/terminal/node/windowsShellHelper'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { TerminalProcessManager } from 'vs/workbench/contrib/terminal/browser/terminalProcessManager'; import { IProcessEnvironment, Platform } from 'vs/base/common/platform'; import { TerminalProcess } from 'vs/workbench/contrib/terminal/node/terminalProcess'; +import * as typeAheadAddon from 'vs/workbench/contrib/terminal/browser/terminalTypeAheadAddon'; import { getDefaultShell } from 'vs/workbench/contrib/terminal/node/terminal'; -import { Terminal as XTermTerminal } from 'xterm'; -import { WebLinksAddon as XTermWebLinksAddon } from 'xterm-addon-web-links'; -import { SearchAddon as XTermSearchAddon } from 'xterm-addon-search'; let Terminal: typeof XTermTerminal; -let WebLinksAddon: typeof XTermWebLinksAddon; -let SearchAddon: typeof XTermSearchAddon; /** * A service used by TerminalInstance (and components owned by it) that allows it to break its @@ -33,29 +32,27 @@ export class TerminalInstanceService implements ITerminalInstanceService { public async getXtermConstructor(): Promise { if (!Terminal) { - Terminal = (await import('xterm')).Terminal; + Terminal = (await import('vscode-xterm')).Terminal; + // Enable xterm.js addons + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/search/search')); + Terminal.applyAddon(require.__$__nodeRequire('vscode-xterm/lib/addons/webLinks/webLinks')); + Terminal.applyAddon(typeAheadAddon); + // Localize strings + Terminal.strings.blankLine = nls.localize('terminal.integrated.a11yBlankLine', 'Blank line'); + Terminal.strings.promptLabel = nls.localize('terminal.integrated.a11yPromptLabel', 'Terminal input'); + Terminal.strings.tooMuchOutput = nls.localize('terminal.integrated.a11yTooMuchOutput', 'Too much output to announce, navigate to rows manually to read'); } return Terminal; } - public async getXtermWebLinksConstructor(): Promise { - if (!WebLinksAddon) { - WebLinksAddon = (await import('xterm-addon-web-links')).WebLinksAddon; - } - return WebLinksAddon; - } - - public async getXtermSearchConstructor(): Promise { - if (!SearchAddon) { - SearchAddon = (await import('xterm-addon-search')).SearchAddon; - } - return SearchAddon; - } - public createWindowsShellHelper(shellProcessId: number, instance: ITerminalInstance, xterm: XTermTerminal): IWindowsShellHelper { return new WindowsShellHelper(shellProcessId, instance, xterm); } + public createTerminalProcessManager(id: number, configHelper: ITerminalConfigHelper): ITerminalProcessManager { + return this._instantiationService.createInstance(TerminalProcessManager, id, configHelper); + } + public createTerminalProcess(shellLaunchConfig: IShellLaunchConfig, cwd: string, cols: number, rows: number, env: IProcessEnvironment, windowsEnableConpty: boolean): ITerminalChildProcess { return this._instantiationService.createInstance(TerminalProcess, shellLaunchConfig, cwd, cols, rows, env, windowsEnableConpty); } diff --git a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts index 15b139c051..93af8cda0a 100644 --- a/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/electron-browser/terminalService.ts @@ -100,6 +100,11 @@ export class TerminalService extends BrowserTerminalService implements ITerminal return getDefaultShell(p); } + public refreshActiveTab(): void { + // Fire active instances changed + this._onActiveTabChanged.fire(); + } + public selectDefaultWindowsShell(): Promise { return this._detectWindowsShells().then(shells => { const options: IPickOptions = { diff --git a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts index 983afd4c04..e8d802cda2 100644 --- a/src/vs/workbench/contrib/terminal/node/terminalProcess.ts +++ b/src/vs/workbench/contrib/terminal/node/terminalProcess.ts @@ -54,7 +54,14 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { this._initialCwd = cwd; - const useConpty = windowsEnableConpty && process.platform === 'win32' && getWindowsBuildNumber() >= 18309; + // Only use ConPTY when the client is non WoW64 (see #72190) and the Windows build number is at least 18309 (for + // stability/performance reasons) + const is32ProcessOn64Windows = process.env.hasOwnProperty('PROCESSOR_ARCHITEW6432'); + const useConpty = windowsEnableConpty && + process.platform === 'win32' && + !is32ProcessOn64Windows && + getWindowsBuildNumber() >= 18309; + const options: pty.IPtyForkOptions | pty.IWindowsPtyForkOptions = { name: shellName, cwd, @@ -193,9 +200,6 @@ export class TerminalProcess implements ITerminalChildProcess, IDisposable { if (this._isDisposed) { return; } - if (typeof cols !== 'number' || typeof rows !== 'number' || isNaN(cols) || isNaN(rows)) { - return; - } // Ensure that cols and rows are always >= 1, this prevents a native // exception in winpty. if (this._ptyProcess) { diff --git a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts index dea63ca619..59f2815e48 100644 --- a/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts +++ b/src/vs/workbench/contrib/terminal/node/windowsShellHelper.ts @@ -6,7 +6,7 @@ import * as platform from 'vs/base/common/platform'; import { Emitter, Event } from 'vs/base/common/event'; import { ITerminalInstance, IWindowsShellHelper } from 'vs/workbench/contrib/terminal/common/terminal'; -import { Terminal as XTermTerminal } from 'xterm'; +import { Terminal as XTermTerminal } from 'vscode-xterm'; import WindowsProcessTreeType = require('windows-process-tree'); const SHELL_EXECUTABLES = [ diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts index fd7c7226ce..87d25074eb 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalCommandTracker.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { Terminal, TerminalCore } from 'xterm'; +import { Terminal, TerminalCore } from 'vscode-xterm'; import { TerminalCommandTracker } from 'vs/workbench/contrib/terminal/browser/terminalCommandTracker'; import { isWindows } from 'vs/base/common/platform'; diff --git a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts index 3c98380fc6..cf3f5a002c 100644 --- a/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts +++ b/src/vs/workbench/contrib/terminal/test/electron-browser/terminalLinkHandler.test.ts @@ -7,7 +7,6 @@ import * as assert from 'assert'; import { Platform, OperatingSystem } from 'vs/base/common/platform'; import { TerminalLinkHandler, LineColumnInfo } from 'vs/workbench/contrib/terminal/browser/terminalLinkHandler'; import * as strings from 'vs/base/common/strings'; -import { ITerminalInstanceService } from 'vs/workbench/contrib/terminal/browser/terminal'; class TestTerminalLinkHandler extends TerminalLinkHandler { public get localLinkRegex(): RegExp { @@ -25,34 +24,10 @@ class TestTerminalLinkHandler extends TerminalLinkHandler { } class TestXterm { - public loadAddon() { } + public webLinksInit() { } public registerLinkMatcher() { } } -class MockTerminalInstanceService implements ITerminalInstanceService { - _serviceBrand: any; - getXtermConstructor(): Promise { - throw new Error('Method not implemented.'); - } - async getXtermWebLinksConstructor(): Promise { - return (await import('xterm-addon-web-links')).WebLinksAddon; - } - getXtermSearchConstructor(): Promise { - throw new Error('Method not implemented.'); - } - createWindowsShellHelper(): any { - throw new Error('Method not implemented.'); - } - createTerminalProcess(): any { - throw new Error('Method not implemented.'); - } - getDefaultShell(p: Platform): string { - throw new Error('Method not implemented.'); - } - - -} - interface LinkFormatInfo { urlFormat: string; line?: string; @@ -65,7 +40,7 @@ suite('Workbench - TerminalLinkHandler', () => { const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, { os: OperatingSystem.Windows, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -140,7 +115,7 @@ suite('Workbench - TerminalLinkHandler', () => { const terminalLinkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, { os: OperatingSystem.Linux, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); function testLink(link: string, linkUrl: string, lineNo?: string, columnNo?: string) { assert.equal(terminalLinkHandler.extractLinkUrl(link), linkUrl); assert.equal(terminalLinkHandler.extractLinkUrl(`:${link}:`), linkUrl); @@ -207,7 +182,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, { os: OperatingSystem.Windows, userHome: 'C:\\Users\\Me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); linkHandler.processCwd = 'C:\\base'; assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base\\src\\file1'); @@ -220,7 +195,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Windows, { os: OperatingSystem.Windows, userHome: 'C:\\Users\\M e' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); linkHandler.processCwd = 'C:\\base dir'; assert.equal(linkHandler.preprocessPath('./src/file1'), 'C:\\base dir\\src\\file1'); @@ -234,7 +209,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, { os: OperatingSystem.Linux, userHome: '/home/me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); linkHandler.processCwd = '/base'; assert.equal(linkHandler.preprocessPath('./src/file1'), '/base/src/file1'); @@ -247,7 +222,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, { os: OperatingSystem.Linux, userHome: '/home/me' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); assert.equal(linkHandler.preprocessPath('./src/file1'), null); assert.equal(linkHandler.preprocessPath('src/file2'), null); @@ -261,7 +236,7 @@ suite('Workbench - TerminalLinkHandler', () => { const linkHandler = new TestTerminalLinkHandler(new TestXterm(), Platform.Linux, { os: OperatingSystem.Linux, userHome: '' - } as any, null!, null!, null!, null!, new MockTerminalInstanceService(), null!); + } as any, null!, null!, null!, null!, null!); function assertAreGoodMatches(matches: RegExpMatchArray | null) { if (matches) { diff --git a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts index 0409f628d5..fc451a1754 100644 --- a/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts +++ b/src/vs/workbench/contrib/terminal/test/node/terminalEnvironment.test.ts @@ -11,14 +11,14 @@ import { IStringDictionary } from 'vs/base/common/collections'; suite('Workbench - TerminalEnvironment', () => { test('addTerminalEnvironmentKeys', () => { - const env: { [key: string]: any } = { FOO: 'bar' }; + const env = { FOO: 'bar' }; const locale = 'en-au'; terminalEnvironment.addTerminalEnvironmentKeys(env, '1.2.3', locale, true); assert.equal(env['TERM_PROGRAM'], 'vscode'); assert.equal(env['TERM_PROGRAM_VERSION'], '1.2.3'); assert.equal(env['LANG'], 'en_AU.UTF-8', 'LANG is equal to the requested locale with UTF-8'); - const env2: { [key: string]: any } = { FOO: 'bar' }; + const env2 = { FOO: 'bar' }; terminalEnvironment.addTerminalEnvironmentKeys(env2, '1.2.3', undefined, true); assert.equal(env2['LANG'], 'en_US.UTF-8', 'LANG is equal to en_US.UTF-8 as fallback.'); // More info on issue #14586 diff --git a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts index b91003dab8..61546d19bb 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.contribution.ts @@ -11,7 +11,7 @@ import { IWorkbenchContributionsRegistry, Extensions as WorkbenchExtensions } fr import { IGlobalActivityRegistry, GlobalActivityExtensions } from 'vs/workbench/common/activity'; import { IWorkbenchActionRegistry, Extensions as ActionExtensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; -import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution } from './update'; +import { ShowCurrentReleaseNotesAction, ProductContribution, UpdateContribution, Win3264BitContribution, Linux32BitContribution } from './update'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; const workbench = Registry.as(WorkbenchExtensions.Workbench); @@ -24,6 +24,13 @@ if (platform.isWindows) { } } +// TODO@ben remove me after a while +if (platform.isLinux) { + if (process.arch === 'ia32') { + workbench.registerWorkbenchContribution(Linux32BitContribution, LifecyclePhase.Restored); + } +} + Registry.as(GlobalActivityExtensions) .registerActivity(UpdateContribution); diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts index 4b8838a8a5..488a9e4959 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.ts @@ -6,7 +6,7 @@ import * as nls from 'vs/nls'; import severity from 'vs/base/common/severity'; import { IAction, Action } from 'vs/base/common/actions'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Separator } from 'vs/base/browser/ui/actionbar/actionbar'; import pkg from 'vs/platform/product/node/package'; import product from 'vs/platform/product/node/product'; @@ -219,6 +219,53 @@ export class Win3264BitContribution implements IWorkbenchContribution { } } +export class Linux32BitContribution implements IWorkbenchContribution { + + private static readonly KEY = 'update/linux32-64bits'; + private static readonly URL = 'https://code.visualstudio.com/updates/v1_32#_linux-32-bit-support-ends-soon'; + private static readonly INSIDER_URL = 'https://github.com/Microsoft/vscode-docs/blob/vnext/release-notes/v1_32.md#linux-32-bit-support-ends-soon'; + + constructor( + @IStorageService storageService: IStorageService, + @INotificationService notificationService: INotificationService, + @IEnvironmentService environmentService: IEnvironmentService + ) { + if (environmentService.disableUpdates) { + return; + } + + const neverShowAgain = new NeverShowAgain(Linux32BitContribution.KEY, storageService); + + if (!neverShowAgain.shouldShow()) { + return; + } + + const url = product.quality === 'insider' + ? Linux32BitContribution.INSIDER_URL + : Linux32BitContribution.URL; + + const handle = notificationService.prompt( + severity.Info, + nls.localize('linux64bits', "{0} for 32-bit Linux will soon be discontinued. Please update to the 64-bit version.", product.nameShort, url), + [{ + label: nls.localize('learnmore', "Learn More"), + run: () => { + window.open(url); + } + }, + { + label: nls.localize('neveragain', "Don't Show Again"), + isSecondary: true, + run: () => { + neverShowAgain.action.run(handle); + neverShowAgain.action.dispose(); + } + }], + { sticky: true } + ); + } +} + class CommandAction extends Action { constructor( @@ -230,7 +277,7 @@ class CommandAction extends Action { } } -export class UpdateContribution extends Disposable implements IGlobalActivity { +export class UpdateContribution implements IGlobalActivity { private static readonly showCommandsId = 'workbench.action.showCommands'; private static readonly openSettingsId = 'workbench.action.openSettings'; @@ -246,6 +293,7 @@ export class UpdateContribution extends Disposable implements IGlobalActivity { private state: UpdateState; private badgeDisposable: IDisposable = Disposable.None; + private disposables: IDisposable[] = []; constructor( @IStorageService private readonly storageService: IStorageService, @@ -257,10 +305,9 @@ export class UpdateContribution extends Disposable implements IGlobalActivity { @IActivityService private readonly activityService: IActivityService, @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService ) { - super(); this.state = updateService.state; - this._register(updateService.onStateChange(this.onUpdateStateChange, this)); + updateService.onStateChange(this.onUpdateStateChange, this, this.disposables); this.onUpdateStateChange(this.updateService.state); /* @@ -538,4 +585,8 @@ export class UpdateContribution extends Disposable implements IGlobalActivity { this.updateService.quitAndInstall()); } } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index ad8e958936..4f436e03c2 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./watermark'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { assign } from 'vs/base/common/objects'; import { isMacintosh, OS } from 'vs/base/common/platform'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; @@ -120,8 +120,9 @@ const folderEntries = [ const WORKBENCH_TIPS_ENABLED_KEY = 'workbench.tips.enabled'; -export class WatermarkContribution extends Disposable implements IWorkbenchContribution { +export class WatermarkContribution implements IWorkbenchContribution { + private toDispose: IDisposable[] = []; private watermark: HTMLElement; private enabled: boolean; private workbenchState: WorkbenchState; @@ -134,7 +135,6 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr @IConfigurationService private readonly configurationService: IConfigurationService, @IEditorGroupsService private readonly editorGroupsService: IEditorGroupsService ) { - super(); this.workbenchState = contextService.getWorkbenchState(); lifecycleService.onShutdown(this.dispose, this); @@ -142,7 +142,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr if (this.enabled) { this.create(); } - this._register(this.configurationService.onDidChangeConfiguration(e => { + this.toDispose.push(this.configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration(WORKBENCH_TIPS_ENABLED_KEY)) { const enabled = this.configurationService.getValue(WORKBENCH_TIPS_ENABLED_KEY); if (enabled !== this.enabled) { @@ -155,7 +155,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr } } })); - this._register(this.contextService.onDidChangeWorkbenchState(e => { + this.toDispose.push(this.contextService.onDidChangeWorkbenchState(e => { const previousWorkbenchState = this.workbenchState; this.workbenchState = this.contextService.getWorkbenchState(); @@ -189,8 +189,8 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr }; update(); dom.prepend(container.firstElementChild as HTMLElement, this.watermark); - this._register(this.keybindingService.onDidUpdateKeybindings(update)); - this._register(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension))); + this.toDispose.push(this.keybindingService.onDidUpdateKeybindings(update)); + this.toDispose.push(this.editorGroupsService.onDidLayout(dimension => this.handleEditorPartSize(container, dimension))); this.handleEditorPartSize(container, this.editorGroupsService.dimension); } @@ -215,6 +215,10 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr this.destroy(); this.create(); } + + public dispose(): void { + this.toDispose = dispose(this.toDispose); + } } Registry.as(WorkbenchExtensions.Workbench) diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts index ab6a0eda7d..eb035a02e6 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditor.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditor.ts @@ -6,7 +6,7 @@ import * as DOM from 'vs/base/browser/dom'; import { CancellationToken } from 'vs/base/common/cancellation'; import { Emitter, Event } from 'vs/base/common/event'; -import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { IStorageService } from 'vs/platform/storage/common/storage'; @@ -33,7 +33,7 @@ export class WebviewEditor extends BaseEditor { private _content?: HTMLElement; private _webviewContent: HTMLElement | undefined; - private readonly _webviewFocusTrackerDisposables = new DisposableStore(); + private _webviewFocusTrackerDisposables: IDisposable[] = []; private _onFocusWindowHandler?: IDisposable; private readonly _onDidFocusWebview = this._register(new Emitter()); @@ -89,7 +89,7 @@ export class WebviewEditor extends BaseEditor { this._content = undefined; } - this._webviewFocusTrackerDisposables.dispose(); + this._webviewFocusTrackerDisposables = dispose(this._webviewFocusTrackerDisposables); if (this._onFocusWindowHandler) { this._onFocusWindowHandler.dispose(); @@ -304,14 +304,14 @@ export class WebviewEditor extends BaseEditor { } private trackFocus() { - this._webviewFocusTrackerDisposables.clear(); + this._webviewFocusTrackerDisposables = dispose(this._webviewFocusTrackerDisposables); // Track focus in webview content const webviewContentFocusTracker = DOM.trackFocus(this._webviewContent!); - this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker); - this._webviewFocusTrackerDisposables.add(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); + this._webviewFocusTrackerDisposables.push(webviewContentFocusTracker); + this._webviewFocusTrackerDisposables.push(webviewContentFocusTracker.onDidFocus(() => this._onDidFocusWebview.fire())); // Track focus in webview element - this._webviewFocusTrackerDisposables.add(this._webview!.onDidFocus(() => this._onDidFocusWebview.fire())); + this._webviewFocusTrackerDisposables.push(this._webview!.onDidFocus(() => this._onDidFocusWebview.fire())); } } diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts index a85720164b..65b46d808a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorInput.ts @@ -327,4 +327,4 @@ export class RevivedWebviewEditorInput extends WebviewEditorInput { } return super.resolve(); } -} +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/webview/browser/webviewService.ts b/src/vs/workbench/contrib/webview/browser/webviewService.ts deleted file mode 100644 index 0f2cc310e7..0000000000 --- a/src/vs/workbench/contrib/webview/browser/webviewService.ts +++ /dev/null @@ -1,15 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IWebviewService, Webview, WebviewContentOptions, WebviewOptions } from 'vs/workbench/contrib/webview/common/webview'; - -export class NullWebviewService implements IWebviewService { - - _serviceBrand: any; - - createWebview(_options: WebviewOptions, _contentOptions: WebviewContentOptions): Webview { - throw new Error('not supported'); - } -} diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index 357d26648a..c3f0a5a9da 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -9,7 +9,6 @@ import { ExtensionIdentifier } from 'vs/platform/extensions/common/extensions'; import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import * as modes from 'vs/editor/common/modes'; -import { IDisposable } from 'vs/base/common/lifecycle'; /** * Set when the find widget in a webview is visible. @@ -46,7 +45,7 @@ export interface WebviewContentOptions { readonly portMappings?: ReadonlyArray; } -export interface Webview extends IDisposable { +export interface Webview { html: string; options: WebviewContentOptions; @@ -69,6 +68,8 @@ export interface Webview extends IDisposable { layout(): void; mountTo(parent: HTMLElement): void; focus(): void; + dispose(): void; + reload(): void; selectAll(): void; diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 62c2974fcd..2b9d8448ad 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -361,10 +361,10 @@ interface WebviewContent { } export class WebviewElement extends Disposable implements Webview { - private _webview: Electron.WebviewTag | undefined; + private _webview: Electron.WebviewTag; private _ready: Promise; - private _webviewFindWidget: WebviewFindWidget | undefined; + private _webviewFindWidget: WebviewFindWidget; private _findStarted: boolean = false; private content: WebviewContent; @@ -404,8 +404,8 @@ export class WebviewElement extends Disposable implements Webview { this._webview.src = 'data:text/html;charset=utf-8,%3C%21DOCTYPE%20html%3E%0D%0A%3Chtml%20lang%3D%22en%22%20style%3D%22width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3Chead%3E%0D%0A%09%3Ctitle%3EVirtual%20Document%3C%2Ftitle%3E%0D%0A%3C%2Fhead%3E%0D%0A%3Cbody%20style%3D%22margin%3A%200%3B%20overflow%3A%20hidden%3B%20width%3A%20100%25%3B%20height%3A%20100%25%22%3E%0D%0A%3C%2Fbody%3E%0D%0A%3C%2Fhtml%3E'; this._ready = new Promise(resolve => { - const subscription = this._register(addDisposableListener(this._webview!, 'ipc-message', (event) => { - if (this._webview && event.channel === 'webview-ready') { + const subscription = this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { + if (event.channel === 'webview-ready') { // console.info('[PID Webview] ' event.args[0]); addClass(this._webview, 'ready'); // can be found by debug command @@ -447,7 +447,7 @@ export class WebviewElement extends Disposable implements Webview { this.layout(); // Workaround for https://github.com/electron/electron/issues/14474 - if (this._webview && (this._focused || document.activeElement === this._webview)) { + if (this._focused || document.activeElement === this._webview) { this._webview.blur(); this._webview.focus(); } @@ -456,10 +456,6 @@ export class WebviewElement extends Disposable implements Webview { console.error('embedded page crashed'); })); this._register(addDisposableListener(this._webview, 'ipc-message', (event) => { - if (!this._webview) { - return; - } - switch (event.channel) { case 'onmessage': if (event.args && event.args.length) { @@ -513,14 +509,10 @@ export class WebviewElement extends Disposable implements Webview { } this.style(themeService.getTheme()); - this._register(themeService.onThemeChange(this.style, this)); + themeService.onThemeChange(this.style, this, this._toDispose); } public mountTo(parent: HTMLElement) { - if (!this._webview) { - return; - } - if (this._webviewFindWidget) { parent.appendChild(this._webviewFindWidget.getDomNode()!); } @@ -532,13 +524,10 @@ export class WebviewElement extends Disposable implements Webview { if (this._webview.parentElement) { this._webview.parentElement.removeChild(this._webview); } - this._webview = undefined; } - if (this._webviewFindWidget) { - this._webviewFindWidget.dispose(); - this._webviewFindWidget = undefined; - } + this._webview = undefined!; + this._webviewFindWidget = undefined!; super.dispose(); } @@ -556,11 +545,7 @@ export class WebviewElement extends Disposable implements Webview { private _send(channel: string, ...args: any[]): void { this._ready - .then(() => { - if (this._webview) { - this._webview.send(channel, ...args); - } - }) + .then(() => this._webview.send(channel, ...args)) .catch(err => console.error(err)); } @@ -619,9 +604,6 @@ export class WebviewElement extends Disposable implements Webview { } public focus(): void { - if (!this._webview) { - return; - } this._webview.focus(); this._send('focus'); @@ -679,9 +661,6 @@ export class WebviewElement extends Disposable implements Webview { } public layout(): void { - if (!this._webview) { - return; - } const contents = this._webview.getWebContents(); if (!contents || contents.isDestroyed()) { return; @@ -700,7 +679,7 @@ export class WebviewElement extends Disposable implements Webview { } public startFind(value: string, options?: Electron.FindInPageOptions) { - if (!value || !this._webview) { + if (!value) { return; } @@ -727,10 +706,6 @@ export class WebviewElement extends Disposable implements Webview { * @param value The string to search for. Empty strings are ignored. */ public find(value: string, previous: boolean): void { - if (!this._webview) { - return; - } - // Searching with an empty value will throw an exception if (!value) { return; @@ -746,9 +721,6 @@ export class WebviewElement extends Disposable implements Webview { } public stopFind(keepSelection?: boolean): void { - if (!this._webview) { - return; - } this._findStarted = false; this._webview.stopFindInPage(keepSelection ? 'keepSelection' : 'clearSelection'); } @@ -770,39 +742,27 @@ export class WebviewElement extends Disposable implements Webview { } public selectAll() { - if (this._webview) { - this._webview.selectAll(); - } + this._webview.selectAll(); } public copy() { - if (this._webview) { - this._webview.copy(); - } + this._webview.copy(); } public paste() { - if (this._webview) { - this._webview.paste(); - } + this._webview.paste(); } public cut() { - if (this._webview) { - this._webview.cut(); - } + this._webview.cut(); } public undo() { - if (this._webview) { - this._webview.undo(); - } + this._webview.undo(); } public redo() { - if (this._webview) { - this._webview.redo(); - } + this._webview.redo(); } } diff --git a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts index a48253928e..ed9b2cd793 100644 --- a/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts +++ b/src/vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay.ts @@ -15,7 +15,7 @@ import { Action } from 'vs/base/common/actions'; import { IWorkbenchActionRegistry, Extensions } from 'vs/workbench/common/actions'; import { SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { RawContextKey, IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { KeyCode } from 'vs/base/common/keyCodes'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; @@ -150,8 +150,9 @@ export class HideWelcomeOverlayAction extends Action { } } -class WelcomeOverlay extends Disposable { +class WelcomeOverlay { + private _toDispose: IDisposable[] = []; private _overlayVisible: IContextKey; private _overlay: HTMLElement; @@ -162,7 +163,6 @@ class WelcomeOverlay extends Disposable { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @IKeybindingService private readonly keybindingService: IKeybindingService ) { - super(); this._overlayVisible = OVERLAY_VISIBLE.bindTo(this._contextKeyService); this.create(); } @@ -177,7 +177,7 @@ class WelcomeOverlay extends Disposable { this._overlay.style.display = 'none'; this._overlay.tabIndex = -1; - this._register(dom.addStandardDisposableListener(this._overlay, 'click', () => this.hide())); + this._toDispose.push(dom.addStandardDisposableListener(this._overlay, 'click', () => this.hide())); this.commandService.onWillExecuteCommand(() => this.hide()); dom.append(this._overlay, $('.commandPalettePlaceholder')); @@ -214,7 +214,7 @@ class WelcomeOverlay extends Disposable { } private updateProblemsKey() { - const problems = document.querySelector('div[id="workbench.parts.statusbar"] .statusbar-item.left .octicon.octicon-warning'); + const problems = document.querySelector('.task-statusbar-item'); const key = this._overlay.querySelector('.key.problems') as HTMLElement; if (problems instanceof HTMLElement) { const target = problems.getBoundingClientRect(); @@ -237,6 +237,10 @@ class WelcomeOverlay extends Disposable { this._overlayVisible.reset(); } } + + dispose() { + this._toDispose = dispose(this._toDispose); + } } // {SQL CARBON EDIT} diff --git a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts index 0ad4931e5f..9104521bc0 100644 --- a/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts +++ b/src/vs/workbench/contrib/welcome/page/browser/welcomePage.ts @@ -26,7 +26,7 @@ import { IExtensionEnablementService, IExtensionManagementService, IExtensionGal // {{SQL CARBON EDIT}} - Redirect to ADS welcome page import { used } from 'sql/workbench/contrib/welcome/page/browser/az_data_welcome_page'; import { ILifecycleService, StartupKind } from 'vs/platform/lifecycle/common/lifecycle'; -import { Disposable } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { splitName } from 'vs/base/common/labels'; import { registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { registerColor, focusBorder, textLinkForeground, textLinkActiveForeground, foreground, descriptionForeground, contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; @@ -246,7 +246,9 @@ const keymapStrings: Strings = { const welcomeInputTypeId = 'workbench.editors.welcomePageInput'; -class WelcomePage extends Disposable { +class WelcomePage { + + private disposables: IDisposable[] = []; readonly editorInput: WalkThroughInput; @@ -266,8 +268,7 @@ class WelcomePage extends Disposable { @ILifecycleService lifecycleService: ILifecycleService, @ITelemetryService private readonly telemetryService: ITelemetryService ) { - super(); - this._register(lifecycleService.onShutdown(() => this.dispose())); + this.disposables.push(lifecycleService.onShutdown(() => this.dispose())); const recentlyOpened = this.windowService.getRecentlyOpened(); const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); @@ -322,14 +323,14 @@ class WelcomePage extends Disposable { ul.append(...listEntries, moreRecent); }; updateEntries(); - this._register(this.labelService.onDidChangeFormatters(updateEntries)); + this.disposables.push(this.labelService.onDidChangeFormatters(updateEntries)); }).then(undefined, onUnexpectedError); this.addExtensionList(container, '.extensionPackList', extensionPacks, extensionPackStrings); this.addExtensionList(container, '.keymapList', keymapExtensions, keymapStrings); this.updateInstalledExtensions(container, installedExtensions); - this._register(this.instantiationService.invokeFunction(onExtensionChanged)(ids => { + this.disposables.push(this.instantiationService.invokeFunction(onExtensionChanged)(ids => { for (const id of ids) { if (container.querySelector(`.installExtension[data-extension="${id.id}"], .enabledExtension[data-extension="${id.id}"]`)) { const installedExtensions = this.instantiationService.invokeFunction(getInstalledExtensions); @@ -594,6 +595,10 @@ class WelcomePage extends Disposable { }); }).then(undefined, onUnexpectedError); } + + dispose(): void { + this.disposables = dispose(this.disposables); + } } export class WelcomeInputFactory implements IEditorInputFactory { diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index f365a8538f..5febf0f2ea 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -8,7 +8,7 @@ import { DomScrollableElement } from 'vs/base/browser/ui/scrollbar/scrollableEle import { ScrollbarVisibility } from 'vs/base/common/scrollable'; import * as strings from 'vs/base/common/strings'; import { URI } from 'vs/base/common/uri'; -import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor'; import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -56,7 +56,7 @@ export class WalkThroughPart extends BaseEditor { static readonly ID: string = 'workbench.editor.walkThroughPart'; - private readonly disposables = new DisposableStore(); + private disposables: IDisposable[] = []; private contentDisposables: IDisposable[] = []; private content: HTMLDivElement; private scrollbar: DomScrollableElement; @@ -92,13 +92,13 @@ export class WalkThroughPart extends BaseEditor { horizontal: ScrollbarVisibility.Auto, vertical: ScrollbarVisibility.Auto }); - this.disposables.add(this.scrollbar); + this.disposables.push(this.scrollbar); container.appendChild(this.scrollbar.getDomNode()); this.registerFocusHandlers(); this.registerClickHandler(); - this.disposables.add(this.scrollbar.onScroll(e => this.updatedScrollPosition())); + this.disposables.push(this.scrollbar.onScroll(e => this.updatedScrollPosition())); } private updatedScrollPosition() { @@ -120,16 +120,16 @@ export class WalkThroughPart extends BaseEditor { } private registerFocusHandlers() { - this.disposables.add(this.addEventListener(this.content, 'mousedown', e => { + this.disposables.push(this.addEventListener(this.content, 'mousedown', e => { this.focus(); })); - this.disposables.add(this.addEventListener(this.content, 'focus', e => { + this.disposables.push(this.addEventListener(this.content, 'focus', e => { this.editorFocus.set(true); })); - this.disposables.add(this.addEventListener(this.content, 'blur', e => { + this.disposables.push(this.addEventListener(this.content, 'blur', e => { this.editorFocus.reset(); })); - this.disposables.add(this.addEventListener(this.content, 'focusin', e => { + this.disposables.push(this.addEventListener(this.content, 'focusin', e => { // Work around scrolling as side-effect of setting focus on the offscreen zone widget (#18929) if (e.target instanceof HTMLElement && e.target.classList.contains('zone-widget-container')) { const scrollPosition = this.scrollbar.getScrollPosition(); @@ -514,7 +514,7 @@ export class WalkThroughPart extends BaseEditor { dispose(): void { this.editorFocus.reset(); this.contentDisposables = dispose(this.contentDisposables); - this.disposables.dispose(); + this.disposables = dispose(this.disposables); super.dispose(); } } diff --git a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts index 1f558f35ea..d8e02a8ec5 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/common/walkThroughInput.ts @@ -6,7 +6,7 @@ import * as strings from 'vs/base/common/strings'; import { EditorInput, EditorModel, ITextEditorModel } from 'vs/workbench/common/editor'; import { URI } from 'vs/base/common/uri'; -import { IReference } from 'vs/base/common/lifecycle'; +import { IReference, IDisposable, dispose } from 'vs/base/common/lifecycle'; import { ITextModelService } from 'vs/editor/common/services/resolverService'; import * as marked from 'vs/base/common/marked/marked'; import { Schemas } from 'vs/base/common/network'; @@ -46,6 +46,8 @@ export interface WalkThroughInputOptions { export class WalkThroughInput extends EditorInput { + private disposables: IDisposable[] = []; + private promise: Promise | null = null; private maxTopScroll = 0; @@ -137,6 +139,8 @@ export class WalkThroughInput extends EditorInput { } dispose(): void { + this.disposables = dispose(this.disposables); + if (this.promise) { this.promise.then(model => model.dispose()); this.promise = null; diff --git a/src/vs/workbench/electron-browser/main.contribution.ts b/src/vs/workbench/electron-browser/main.contribution.ts index 8f388b1353..4116bbcbdb 100644 --- a/src/vs/workbench/electron-browser/main.contribution.ts +++ b/src/vs/workbench/electron-browser/main.contribution.ts @@ -21,7 +21,7 @@ import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/co import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; import { ADD_ROOT_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands'; -import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteFileDialogContext, IsFullscreenContext } from 'vs/workbench/browser/contextkeys'; +import { SupportsWorkspacesContext, IsMacContext, HasMacNativeTabsContext, IsDevelopmentContext, WorkbenchStateContext, WorkspaceFolderCountContext, RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; import { NoEditorsVisibleContext, SingleEditorGroupsContext } from 'vs/workbench/common/editor'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; import { LogStorageAction } from 'vs/platform/storage/node/storageService'; @@ -376,8 +376,7 @@ import { InstallVSIXAction } from 'vs/workbench/contrib/extensions/electron-brow group: '1_toggle_view', command: { id: ToggleFullScreenAction.ID, - title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "&&Full Screen"), - toggled: IsFullscreenContext + title: nls.localize({ key: 'miToggleFullScreen', comment: ['&& denotes a mnemonic'] }, "Toggle &&Full Screen") }, order: 1 }); diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 092ccb0370..a2d7daece9 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -23,6 +23,7 @@ import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { webFrame } from 'electron'; import { ISingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, reviveWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; +import { createBufferSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ConsoleLogService, MultiplexLogService, ILogService } from 'vs/platform/log/common/log'; import { StorageService } from 'vs/platform/storage/node/storageService'; import { LogLevelSetterChannelClient, FollowerLogService } from 'vs/platform/log/node/logIpc'; @@ -48,7 +49,6 @@ import { REMOTE_FILE_SYSTEM_CHANNEL_NAME, RemoteExtensionsFileSystemProvider } f import { DefaultConfigurationExportHelper } from 'vs/workbench/services/configuration/node/configurationExportHelper'; import { ConfigurationCache } from 'vs/workbench/services/configuration/node/configurationCache'; import { ConfigurationFileService } from 'vs/workbench/services/configuration/node/configurationFileService'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; class CodeRendererMain extends Disposable { @@ -230,7 +230,7 @@ class CodeRendererMain extends Disposable { // Multi-root workspace if (this.configuration.workspace) { - return this.configuration.workspace; + return Promise.resolve(this.configuration.workspace); } // Single-folder workspace @@ -260,7 +260,7 @@ class CodeRendererMain extends Disposable { // Return early the folder is not local if (folderUri.scheme !== Schemas.file) { - return { id: createHash('md5').update(folderUri.toString()).digest('hex'), folder: folderUri }; + return Promise.resolve({ id: createHash('md5').update(folderUri.toString()).digest('hex'), folder: folderUri }); } function computeLocalDiskFolderId(folder: URI, stat: fs.Stats): string { @@ -303,7 +303,7 @@ class CodeRendererMain extends Disposable { const configurationFileService = new ConfigurationFileService(); configurationFileService.fileService = fileService; - const workspaceService = new WorkspaceService({ userSettingsResource: environmentService.settingsResource, remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), remoteAuthority: this.configuration.remoteAuthority, configurationCache: new ConfigurationCache(environmentService) }, configurationFileService, remoteAgentService); try { await workspaceService.initialize(payload); @@ -334,7 +334,7 @@ class CodeRendererMain extends Disposable { } private createLogService(mainProcessService: IMainProcessService, environmentService: IWorkbenchEnvironmentService): ILogService { - const spdlogService = new SpdLogService(`renderer${this.configuration.windowId}`, environmentService.logsPath, this.configuration.logLevel); + const spdlogService = createBufferSpdLogService(`renderer${this.configuration.windowId}`, this.configuration.logLevel, environmentService.logsPath); const consoleLogService = new ConsoleLogService(this.configuration.logLevel); const logService = new MultiplexLogService([consoleLogService, spdlogService]); const logLevelClient = new LogLevelSetterChannelClient(mainProcessService.getChannel('loglevel')); diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 75e0a967bf..068ced2e25 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -28,7 +28,7 @@ import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/ import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { fillInActionBarActions } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IDisposable, Disposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; @@ -61,7 +61,7 @@ export class ElectronWindow extends Disposable { private touchBarMenu?: IMenu; private touchBarUpdater: RunOnceScheduler; - private readonly touchBarDisposables = this._register(new DisposableStore()); + private touchBarDisposables: IDisposable[]; private lastInstalledTouchedBar: ICommandAction[][]; private previousConfiguredZoomLevel: number; @@ -95,6 +95,8 @@ export class ElectronWindow extends Disposable { ) { super(); + this.touchBarDisposables = []; + this.pendingFoldersToAdd = []; this.addFoldersScheduler = this._register(new RunOnceScheduler(() => this.doAddFolders(), 100)); @@ -312,24 +314,22 @@ export class ElectronWindow extends Disposable { this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure })); // Root warning - this.lifecycleService.when(LifecyclePhase.Restored).then(() => { - let isAdminPromise: Promise; + this.lifecycleService.when(LifecyclePhase.Restored).then(async () => { + let isAdmin: boolean; if (isWindows) { - isAdminPromise = import('native-is-elevated').then(isElevated => isElevated()); // not using async here due to https://github.com/microsoft/vscode/issues/74321 + const isElevated = await import('native-is-elevated'); + isAdmin = isElevated(); } else { - isAdminPromise = Promise.resolve(isRootUser()); + isAdmin = isRootUser(); } - return isAdminPromise.then(isAdmin => { + // Update title + this.titleService.updateProperties({ isAdmin }); - // Update title - this.titleService.updateProperties({ isAdmin }); - - // Show warning message (unix only) - if (isAdmin && !isWindows) { - this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort)); - } - }); + // Show warning message (unix only) + if (isAdmin && !isWindows) { + this.notificationService.warn(nls.localize('runningAsRoot', "It is not recommended to run {0} as root user.", product.nameShort)); + } }); // Touchbar menu (if enabled) @@ -350,20 +350,20 @@ export class ElectronWindow extends Disposable { } // Dispose old - this.touchBarDisposables.clear(); + this.touchBarDisposables = dispose(this.touchBarDisposables); this.touchBarMenu = undefined; // Create new (delayed) this.touchBarUpdater = new RunOnceScheduler(() => this.doUpdateTouchbarMenu(), 300); - this.touchBarDisposables.add(this.touchBarUpdater); + this.touchBarDisposables.push(this.touchBarUpdater); this.touchBarUpdater.schedule(); } private doUpdateTouchbarMenu(): void { if (!this.touchBarMenu) { this.touchBarMenu = this.editorService.invokeWithinEditorContext(accessor => this.menuService.createMenu(MenuId.TouchBarContext, accessor.get(IContextKeyService))); - this.touchBarDisposables.add(this.touchBarMenu); - this.touchBarDisposables.add(this.touchBarMenu.onDidChange(() => this.touchBarUpdater.schedule())); + this.touchBarDisposables.push(this.touchBarMenu); + this.touchBarDisposables.push(this.touchBarMenu.onDidChange(() => this.touchBarUpdater.schedule())); } const actions: Array = []; @@ -531,4 +531,10 @@ export class ElectronWindow extends Disposable { // Otherwise open all return this.editorService.openEditors(resources); } + + dispose(): void { + this.touchBarDisposables = dispose(this.touchBarDisposables); + + super.dispose(); + } } diff --git a/src/vs/workbench/services/backup/node/backupFileService.ts b/src/vs/workbench/services/backup/node/backupFileService.ts index 1632bc8008..ef880c0dca 100644 --- a/src/vs/workbench/services/backup/node/backupFileService.ts +++ b/src/vs/workbench/services/backup/node/backupFileService.ts @@ -352,7 +352,7 @@ class BackupFileServiceImpl implements IBackupFileService { export class InMemoryBackupFileService implements IBackupFileService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; private backups: Map = new Map(); diff --git a/src/vs/workbench/services/broadcast/common/broadcast.ts b/src/vs/workbench/services/broadcast/common/broadcast.ts new file mode 100644 index 0000000000..a6a9151020 --- /dev/null +++ b/src/vs/workbench/services/broadcast/common/broadcast.ts @@ -0,0 +1,30 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; +import { Event } from 'vs/base/common/event'; + +export const IBroadcastService = createDecorator('broadcastService'); + +export interface IBroadcast { + channel: string; + payload: any; +} + +export interface IBroadcastService { + _serviceBrand: any; + + onBroadcast: Event; + + broadcast(b: IBroadcast): void; +} + +export class NullBroadcastService implements IBroadcastService { + _serviceBrand: any; + onBroadcast: Event = Event.None; + broadcast(_b: IBroadcast): void { + + } +} diff --git a/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts new file mode 100644 index 0000000000..d278ceba6a --- /dev/null +++ b/src/vs/workbench/services/broadcast/electron-browser/broadcastService.ts @@ -0,0 +1,51 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { Event, Emitter } from 'vs/base/common/event'; +import { ipcRenderer as ipc } from 'electron'; +import { ILogService } from 'vs/platform/log/common/log'; +import { Disposable } from 'vs/base/common/lifecycle'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { IWindowService } from 'vs/platform/windows/common/windows'; +import { IBroadcastService, IBroadcast } from 'vs/workbench/services/broadcast/common/broadcast'; + +class BroadcastService extends Disposable implements IBroadcastService { + _serviceBrand: any; + + private readonly _onBroadcast: Emitter = this._register(new Emitter()); + get onBroadcast(): Event { return this._onBroadcast.event; } + + private windowId: number; + + constructor( + @IWindowService readonly windowService: IWindowService, + @ILogService private readonly logService: ILogService + ) { + super(); + + this.windowId = windowService.windowId; + + this.registerListeners(); + } + + private registerListeners(): void { + ipc.on('vscode:broadcast', (event: unknown, b: IBroadcast) => { + this.logService.trace(`Received broadcast from main in window ${this.windowId}: `, b); + + this._onBroadcast.fire(b); + }); + } + + broadcast(b: IBroadcast): void { + this.logService.trace(`Sending broadcast to main from window ${this.windowId}: `, b); + + ipc.send('vscode:broadcast', this.windowId, { + channel: b.channel, + payload: b.payload + }); + } +} + +registerSingleton(IBroadcastService, BroadcastService, true); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index f064b553b7..01ae4ffdab 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -21,8 +21,8 @@ import { extname, join } from 'vs/base/common/path'; import { equals } from 'vs/base/common/objects'; import { Schemas } from 'vs/base/common/network'; import { IConfigurationModel, compare } from 'vs/platform/configuration/common/configuration'; +import { createSHA1 } from 'vs/base/browser/hash'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { hash } from 'vs/base/common/hash'; export class RemoteUserConfiguration extends Disposable { @@ -672,7 +672,7 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati readonly onDidChange: Event = this._onDidChange.event; private configurationModel: ConfigurationModel; - private readonly key: ConfigurationKey; + private readonly key: Thenable; constructor( folder: URI, @@ -680,13 +680,14 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati private readonly configurationCache: IConfigurationCache ) { super(); - this.key = { type: 'folder', key: hash(join(folder.path, configFolderRelativePath)).toString(16) }; + this.key = createSHA1(join(folder.path, configFolderRelativePath)).then(key => ({ type: 'folder', key })); this.configurationModel = new ConfigurationModel(); } async loadConfiguration(): Promise { try { - const contents = await this.configurationCache.read(this.key); + const key = await this.key; + const contents = await this.configurationCache.read(key); const parsed: IConfigurationModel = JSON.parse(contents.toString()); this.configurationModel = new ConfigurationModel(parsed.contents, parsed.keys, parsed.overrides); } catch (e) { @@ -695,10 +696,11 @@ class CachedFolderConfiguration extends Disposable implements IFolderConfigurati } async updateConfiguration(configurationModel: ConfigurationModel): Promise { + const key = await this.key; if (configurationModel.keys.length) { - await this.configurationCache.write(this.key, JSON.stringify(configurationModel.toJSON())); + await this.configurationCache.write(key, JSON.stringify(configurationModel.toJSON())); } else { - await this.configurationCache.remove(this.key); + await this.configurationCache.remove(key); } } diff --git a/src/vs/workbench/services/configuration/browser/configurationCache.ts b/src/vs/workbench/services/configuration/browser/configurationCache.ts deleted file mode 100644 index 4089b4d5cb..0000000000 --- a/src/vs/workbench/services/configuration/browser/configurationCache.ts +++ /dev/null @@ -1,22 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { IConfigurationCache, ConfigurationKey } from 'vs/workbench/services/configuration/common/configuration'; - -export class ConfigurationCache implements IConfigurationCache { - - constructor() { - } - - async read(key: ConfigurationKey): Promise { - return ''; - } - - async write(key: ConfigurationKey, content: string): Promise { - } - - async remove(key: ConfigurationKey): Promise { - } -} \ No newline at end of file diff --git a/src/vs/workbench/services/configuration/common/configurationEditingService.ts b/src/vs/workbench/services/configuration/common/configurationEditingService.ts index 404feb75ef..73725d8b0e 100644 --- a/src/vs/workbench/services/configuration/common/configurationEditingService.ts +++ b/src/vs/workbench/services/configuration/common/configurationEditingService.ts @@ -528,7 +528,7 @@ export class ConfigurationEditingService { private getConfigurationFileResource(target: EditableConfigurationTarget, config: IConfigurationValue, relativePath: string, resource: URI | null | undefined): URI | null { if (target === EditableConfigurationTarget.USER_LOCAL) { - return this.environmentService.settingsResource; + return URI.file(this.environmentService.appSettingsPath); } if (target === EditableConfigurationTarget.USER_REMOTE) { return this.remoteSettingsResource; diff --git a/src/vs/workbench/services/configuration/common/jsonEditingService.ts b/src/vs/workbench/services/configuration/common/jsonEditingService.ts index 122041d4dd..c897ba7570 100644 --- a/src/vs/workbench/services/configuration/common/jsonEditingService.ts +++ b/src/vs/workbench/services/configuration/common/jsonEditingService.ts @@ -39,11 +39,10 @@ export class JSONEditingService implements IJSONEditingService { return Promise.resolve(this.queue.queue(() => this.doWriteConfiguration(resource, value, save))); // queue up writes to prevent race conditions } - private async doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): Promise { - const reference = await this.resolveAndValidate(resource, save); - await this.writeToBuffer(reference.object.textEditorModel, value); - - reference.dispose(); + private doWriteConfiguration(resource: URI, value: IJSONValue, save: boolean): Promise { + return this.resolveAndValidate(resource, save) + .then(reference => this.writeToBuffer(reference.object.textEditorModel, value) + .then(() => reference.dispose())); } private async writeToBuffer(model: ITextModel, value: IJSONValue): Promise { @@ -98,21 +97,21 @@ export class JSONEditingService implements IJSONEditingService { return parseErrors.length > 0; } - private async resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { - const reference = await this.resolveModelReference(resource); + private resolveAndValidate(resource: URI, checkDirty: boolean): Promise> { + return this.resolveModelReference(resource) + .then(reference => { + const model = reference.object.textEditorModel; - const model = reference.object.textEditorModel; + if (this.hasParseErrors(model)) { + return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); + } - if (this.hasParseErrors(model)) { - return this.reject>(JSONEditingErrorCode.ERROR_INVALID_FILE); - } - - // Target cannot be dirty if not writing into buffer - if (checkDirty && this.textFileService.isDirty(resource)) { - return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); - } - - return reference; + // Target cannot be dirty if not writing into buffer + if (checkDirty && this.textFileService.isDirty(resource)) { + return this.reject>(JSONEditingErrorCode.ERROR_FILE_DIRTY); + } + return reference; + }); } private reject(code: JSONEditingErrorCode): Promise { diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts index 25318c58f5..a711f8b6b8 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationEditingService.test.ts @@ -47,7 +47,7 @@ class SettingsTestEnvironmentService extends EnvironmentService { super(args, _execPath); } - get settingsResource(): URI { return URI.file(this.customAppSettingsHome); } + get appSettingsPath(): string { return this.customAppSettingsHome; } } suite('ConfigurationEditingService', () => { @@ -106,7 +106,7 @@ suite('ConfigurationEditingService', () => { instantiationService.stub(IEnvironmentService, environmentService); const remoteAgentService = instantiationService.createInstance(RemoteAgentService, {}); instantiationService.stub(IRemoteAgentService, remoteAgentService); - const workspaceService = new WorkspaceService({ userSettingsResource: environmentService.settingsResource, configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), remoteAgentService); + const workspaceService = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache: new ConfigurationCache(environmentService) }, new ConfigurationFileService(), remoteAgentService); instantiationService.stub(IWorkspaceContextService, workspaceService); return workspaceService.initialize(noWorkspace ? { id: '' } : { folder: URI.file(workspaceDir), id: createHash('md5').update(URI.file(workspaceDir).toString()).digest('hex') }).then(() => { instantiationService.stub(IConfigurationService, workspaceService); @@ -187,7 +187,7 @@ suite('ConfigurationEditingService', () => { test('do not notify error', () => { instantiationService.stub(ITextFileService, 'isDirty', true); const target = sinon.stub(); - instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null!, notify: null!, error: null!, info: null!, warn: null!, status: null! }); + instantiationService.stub(INotificationService, { prompt: target, _serviceBrand: null, notify: null!, error: null!, info: null!, warn: null! }); return testObject.writeConfiguration(EditableConfigurationTarget.USER_LOCAL, { key: 'configurationEditing.service.testSetting', value: 'value' }, { donotNotifyError: true }) .then(() => assert.fail('Should fail with ERROR_CONFIGURATION_FILE_DIRTY error.'), (error: ConfigurationEditingError) => { diff --git a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts index 8e9d1d0886..6c0b3a728d 100644 --- a/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts +++ b/src/vs/workbench/services/configuration/test/electron-browser/configurationService.test.ts @@ -44,7 +44,6 @@ import { ConfigurationCache } from 'vs/workbench/services/configuration/node/con import { ConfigurationFileService } from 'vs/workbench/services/configuration/node/configurationFileService'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IConfigurationCache } from 'vs/workbench/services/configuration/common/configuration'; -import { VSBuffer } from 'vs/base/common/buffer'; class SettingsTestEnvironmentService extends EnvironmentService { @@ -52,7 +51,7 @@ class SettingsTestEnvironmentService extends EnvironmentService { super(args, _execPath); } - get settingsResource(): URI { return URI.file(this.customAppSettingsHome); } + get appSettingsPath(): string { return this.customAppSettingsHome; } } function setUpFolderWorkspace(folderName: string): Promise<{ parentDir: string, folderDir: string }> { @@ -154,7 +153,7 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { const configurationFileService = new ConfigurationFileService(); configurationFileService.fileService = fileService; const configurationCache: IConfigurationCache = { read: () => Promise.resolve(''), write: () => Promise.resolve(), remove: () => Promise.resolve() }; - testObject = new WorkspaceService({ userSettingsResource: environmentService.settingsResource, configurationCache, remoteAuthority }, configurationFileService, remoteAgentService); + testObject = new WorkspaceService({ userSettingsResource: URI.file(environmentService.appSettingsPath), configurationCache, remoteAuthority }, configurationFileService, remoteAgentService); instantiationService.stub(IWorkspaceContextService, testObject); instantiationService.stub(IConfigurationService, testObject); instantiationService.stub(IEnvironmentService, environmentService); @@ -248,26 +247,26 @@ suite('WorkspaceConfigurationService - Remote Folder', () => { return promise; }); - test('update remote settings', async () => { - registerRemoteFileSystemProvider(); - resolveRemoteEnvironment(); - await initialize(); - assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); - const promise = new Promise((c, e) => { - testObject.onDidChangeConfiguration(event => { - try { - assert.equal(event.source, ConfigurationTarget.USER); - assert.deepEqual(event.affectedKeys, ['configurationService.remote.machineSetting']); - assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); - c(); - } catch (error) { - e(error); - } - }); - }); - await instantiationService.get(IFileService).writeFile(URI.file(remoteSettingsFile), VSBuffer.fromString('{ "configurationService.remote.machineSetting": "remoteValue" }')); - return promise; - }); + // test('update remote settings', async () => { + // registerRemoteFileSystemProvider(); + // resolveRemoteEnvironment(); + // await initialize(); + // assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'isSet'); + // const promise = new Promise((c, e) => { + // testObject.onDidChangeConfiguration(event => { + // try { + // assert.equal(event.source, ConfigurationTarget.USER); + // assert.deepEqual(event.affectedKeys, ['configurationService.remote.machineSetting']); + // assert.equal(testObject.getValue('configurationService.remote.machineSetting'), 'remoteValue'); + // c(); + // } catch (error) { + // e(error); + // } + // }); + // }); + // fs.writeFileSync(remoteSettingsFile, '{ "configurationService.remote.machineSetting": "remoteValue" }'); + // return promise; + // }); test('machine settings in local user settings does not override defaults', async () => { fs.writeFileSync(globalSettingsFile, '{ "configurationService.remote.machineSetting": "globalValue" }'); diff --git a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts index d29975910a..f3a66bf4e4 100644 --- a/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts +++ b/src/vs/workbench/services/contextmenu/electron-browser/contextmenuService.ts @@ -115,7 +115,7 @@ class NativeContextMenuService extends Disposable implements IContextMenuService } } - private createMenu(delegate: IContextMenuDelegate, entries: ReadonlyArray, onHide: () => void): IContextMenuItem[] { + private createMenu(delegate: IContextMenuDelegate, entries: Array, onHide: () => void): IContextMenuItem[] { const actionRunner = delegate.actionRunner || new ActionRunner(); return entries.map(entry => this.createMenuItem(delegate, entry, actionRunner, onHide)); diff --git a/src/vs/workbench/services/decorations/browser/decorationsService.ts b/src/vs/workbench/services/decorations/browser/decorationsService.ts index c3c233a680..dec166f697 100644 --- a/src/vs/workbench/services/decorations/browser/decorationsService.ts +++ b/src/vs/workbench/services/decorations/browser/decorationsService.ts @@ -7,7 +7,7 @@ import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; import { IDecorationsService, IDecoration, IResourceDecorationChangeEvent, IDecorationsProvider, IDecorationData } from './decorations'; import { TernarySearchTree } from 'vs/base/common/map'; -import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import { isThenable } from 'vs/base/common/async'; import { LinkedList } from 'vs/base/common/linkedList'; import { createStyleSheet, createCSSRule, removeCSSRulesContainingSelector } from 'vs/base/browser/dom'; @@ -95,20 +95,20 @@ class DecorationRule { } } -class DecorationStyles extends Disposable { +class DecorationStyles { + private readonly _disposables: IDisposable[]; private readonly _styleElement = createStyleSheet(); private readonly _decorationRules = new Map(); constructor( private _themeService: IThemeService, ) { - super(); - this._register(this._themeService.onThemeChange(this._onThemeChange, this)); + this._disposables = [this._themeService.onThemeChange(this._onThemeChange, this)]; } dispose(): void { - super.dispose(); + dispose(this._disposables); const parent = this._styleElement.parentElement; if (parent) { diff --git a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts index 281cf67b9e..e9821d1030 100644 --- a/src/vs/workbench/services/dialogs/browser/fileDialogService.ts +++ b/src/vs/workbench/services/dialogs/browser/fileDialogService.ts @@ -86,7 +86,6 @@ export class FileDialogService implements IFileDialogService { private shouldUseSimplified(schema: string): boolean { const setting = this.configurationService.getValue('files.simpleDialog.enable'); - return (schema !== Schemas.file) || (setting === true); } @@ -94,7 +93,7 @@ export class FileDialogService implements IFileDialogService { return schema !== Schemas.file ? [schema, Schemas.file] : [schema]; } - async pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { + pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -104,23 +103,21 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - - const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); - - if (uri) { - const stat = await this.fileService.resolve(uri); - - const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; - return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); - } - - return; + return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { + if (uri) { + return (this.fileService.resolve(uri)).then(stat => { + const toOpen: IURIToOpen = stat.isDirectory ? { folderUri: uri } : { fileUri: uri }; + return this.windowService.openWindow([toOpen], { forceNewWindow: options.forceNewWindow }); + }); + } + return undefined; + }); } return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options)); } - async pickFileAndOpen(options: IPickAndOpenOptions): Promise { + pickFileAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -130,19 +127,18 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFile.title', 'Open File'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - - const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); - if (uri) { - return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - - return; + return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { + if (uri) { + return this.windowService.openWindow([{ fileUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + return undefined; + }); } return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options)); } - async pickFolderAndOpen(options: IPickAndOpenOptions): Promise { + pickFolderAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -152,19 +148,18 @@ export class FileDialogService implements IFileDialogService { if (this.shouldUseSimplified(schema)) { const title = nls.localize('openFolder.title', 'Open Folder'); const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - - const uri = await this.pickRemoteResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }); - if (uri) { - return this.windowService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - - return; + return this.pickRemoteResource({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }).then(uri => { + if (uri) { + return this.windowService.openWindow([{ folderUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + return undefined; + }); } return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options)); } - async pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { + pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise { const schema = this.getFileSystemSchema(options); if (!options.defaultUri) { @@ -175,13 +170,12 @@ export class FileDialogService implements IFileDialogService { const title = nls.localize('openWorkspace.title', 'Open Workspace'); const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }]; const availableFileSystems = this.ensureFileSchema(schema); // always allow file as well - - const uri = await this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }); - if (uri) { - return this.windowService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); - } - - return; + return this.pickRemoteResource({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }).then(uri => { + if (uri) { + return this.windowService.openWindow([{ workspaceUri: uri }], { forceNewWindow: options.forceNewWindow }); + } + return undefined; + }); } return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options)); @@ -196,34 +190,33 @@ export class FileDialogService implements IFileDialogService { }; } - async showSaveDialog(options: ISaveDialogOptions): Promise { + showSaveDialog(options: ISaveDialogOptions): Promise { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { options.availableFileSystems = [schema]; // by default only allow saving in the own file system } - return this.saveRemoteResource(options); } - const result = await this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)); - if (result) { - return URI.file(result); - } + return this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)).then(result => { + if (result) { + return URI.file(result); + } - return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check + return undefined; + }); } - async showOpenDialog(options: IOpenDialogOptions): Promise { + showOpenDialog(options: IOpenDialogOptions): Promise { const schema = this.getFileSystemSchema(options); if (this.shouldUseSimplified(schema)) { if (!options.availableFileSystems) { options.availableFileSystems = [schema]; // by default only allow loading in the own file system } - - const uri = await this.pickRemoteResource(options); - - return uri ? [uri] : undefined; + return this.pickRemoteResource(options).then(uri => { + return uri ? [uri] : undefined; + }); } const defaultUri = options.defaultUri; @@ -250,20 +243,16 @@ export class FileDialogService implements IFileDialogService { newOptions.properties!.push('multiSelections'); } - const result = await this.windowService.showOpenDialog(newOptions); - - return result ? result.map(URI.file) : undefined; + return this.windowService.showOpenDialog(newOptions).then(result => result ? result.map(URI.file) : undefined); } private pickRemoteResource(options: IOpenDialogOptions): Promise { const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); - return remoteFileDialog.showOpenDialog(options); } private saveRemoteResource(options: ISaveDialogOptions): Promise { const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog); - return remoteFileDialog.showSaveDialog(options); } @@ -274,6 +263,7 @@ export class FileDialogService implements IFileDialogService { private getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string { return options.availableFileSystems && options.availableFileSystems[0] || options.defaultUri && options.defaultUri.scheme || this.getSchemeFilterForWindow(); } + } function isUntitledWorkspace(path: URI, environmentService: IWorkbenchEnvironmentService): boolean { diff --git a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts index 8c52d45c4b..604bb31337 100644 --- a/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts +++ b/src/vs/workbench/services/dialogs/browser/remoteFileDialog.ts @@ -28,8 +28,6 @@ import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { isValidBasename } from 'vs/base/common/extpath'; import { RemoteFileDialogContext } from 'vs/workbench/browser/contextkeys'; -import { Emitter } from 'vs/base/common/event'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; interface FileQuickPickItem extends IQuickPickItem { uri: URI; @@ -62,11 +60,6 @@ export class RemoteFileDialog { private badPath: string | undefined; private remoteAgentEnvironment: IRemoteAgentEnvironment | null; private separator: string; - private onBusyChangeEmitter = new Emitter(); - - protected disposables: IDisposable[] = [ - this.onBusyChangeEmitter - ]; constructor( @IFileService private readonly fileService: IFileService, @@ -86,17 +79,6 @@ export class RemoteFileDialog { this.contextKey = RemoteFileDialogContext.bindTo(contextKeyService); } - set busy(busy: boolean) { - if (this.filePickBox.busy !== busy) { - this.filePickBox.busy = busy; - this.onBusyChangeEmitter.fire(busy); - } - } - - get busy(): boolean { - return this.filePickBox.busy; - } - public async showOpenDialog(options: IOpenDialogOptions = {}): Promise { this.scheme = this.getScheme(options.defaultUri, options.availableFileSystems); this.userHome = await this.getUserHome(); @@ -203,7 +185,7 @@ export class RemoteFileDialog { return new Promise(async (resolve) => { this.filePickBox = this.quickInputService.createQuickPick(); - this.busy = true; + this.filePickBox.busy = true; this.filePickBox.matchOnLabel = false; this.filePickBox.autoFocusOnList = false; this.filePickBox.ignoreFocusOut = true; @@ -221,7 +203,7 @@ export class RemoteFileDialog { } } - let isResolving: number = 0; + let isResolving = false; let isAcceptHandled = false; this.currentFolder = homedir; this.userEnteredPathSegment = ''; @@ -236,16 +218,15 @@ export class RemoteFileDialog { resolve(uri); dialog.contextKey.set(false); dialog.filePickBox.dispose(); - dispose(dialog.disposables); } this.filePickBox.onDidCustom(() => { - if (isAcceptHandled || this.busy) { + if (isAcceptHandled || this.filePickBox.busy) { return undefined; // {{SQL CARBON EDIT}} @todo anthonydresser return to return; when we do strict null checks } isAcceptHandled = true; - isResolving++; + isResolving = true; if (this.options.availableFileSystems && (this.options.availableFileSystems.length > 1)) { this.options.availableFileSystems.shift(); } @@ -262,38 +243,25 @@ export class RemoteFileDialog { } }); - function handleAccept(dialog: RemoteFileDialog) { - if (dialog.busy) { - // Save the accept until the file picker is not busy. - dialog.onBusyChangeEmitter.event((busy: boolean) => { - if (!busy) { - handleAccept(dialog); - } - }); - return; - } else if (isAcceptHandled) { + this.filePickBox.onDidAccept(_ => { + if (isAcceptHandled || this.filePickBox.busy) { return; } isAcceptHandled = true; - isResolving++; - dialog.onDidAccept().then(resolveValue => { + isResolving = true; + this.onDidAccept().then(resolveValue => { if (resolveValue) { - dialog.filePickBox.hide(); - doResolve(dialog, resolveValue); - } else if (dialog.hidden) { - doResolve(dialog, undefined); + this.filePickBox.hide(); + doResolve(this, resolveValue); + } else if (this.hidden) { + doResolve(this, undefined); } else { - isResolving--; + isResolving = false; isAcceptHandled = false; } }); - } - - this.filePickBox.onDidAccept(_ => { - handleAccept(this); }); - this.filePickBox.onDidChangeActive(i => { isAcceptHandled = false; // update input box to match the first selected item @@ -328,7 +296,7 @@ export class RemoteFileDialog { }); this.filePickBox.onDidHide(() => { this.hidden = true; - if (isResolving === 0) { + if (!isResolving) { doResolve(this, undefined); } }); @@ -341,7 +309,7 @@ export class RemoteFileDialog { } else { this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; } - this.busy = false; + this.filePickBox.busy = false; }); } @@ -372,15 +340,14 @@ export class RemoteFileDialog { const relativePath = resources.relativePath(currentDisplayUri, directUri); const isSameRoot = (this.filePickBox.value.length > 1 && currentPath.length > 1) ? equalsIgnoreCase(this.filePickBox.value.substr(0, 2), currentPath.substr(0, 2)) : false; if (relativePath && isSameRoot) { - const path = resources.joinPath(this.currentFolder, relativePath); - return resources.hasTrailingPathSeparator(directUri) ? resources.addTrailingPathSeparator(path) : path; + return resources.joinPath(this.currentFolder, relativePath); } else { return directUri; } } private async onDidAccept(): Promise { - this.busy = true; + this.filePickBox.busy = true; if (this.filePickBox.activeItems.length === 1) { const item = this.filePickBox.selectedItems[0]; if (item.isFolder) { @@ -390,9 +357,10 @@ export class RemoteFileDialog { // When possible, cause the update to happen by modifying the input box. // This allows all input box updates to happen first, and uses the same code path as the user typing. const newPath = this.pathFromUri(item.uri); - if (startsWithIgnoreCase(newPath, this.filePickBox.value) && (equalsIgnoreCase(item.label, resources.basename(item.uri)))) { - this.filePickBox.valueSelection = [this.pathFromUri(this.currentFolder).length, this.filePickBox.value.length]; - this.insertText(newPath, item.label); + if (startsWithIgnoreCase(newPath, this.filePickBox.value)) { + const insertValue = newPath.substring(this.filePickBox.value.length, newPath.length); + this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; + this.insertText(newPath, insertValue); } else if ((item.label === '..') && startsWithIgnoreCase(this.filePickBox.value, newPath)) { this.filePickBox.valueSelection = [newPath.length, this.filePickBox.value.length]; this.insertText(newPath, ''); @@ -400,13 +368,11 @@ export class RemoteFileDialog { await this.updateItems(item.uri, true); } } - this.filePickBox.busy = false; return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check } } else { // If the items have updated, don't try to resolve if ((await this.tryUpdateItems(this.filePickBox.value, this.filePickBoxValue())) !== UpdateResult.NotUpdated) { - this.filePickBox.busy = false; return undefined; // {{SQL CARBON EDIT}} @anthonydresser strict-null-check } } @@ -422,10 +388,10 @@ export class RemoteFileDialog { resolveValue = this.addPostfix(resolveValue); } if (await this.validate(resolveValue)) { - this.busy = false; + this.filePickBox.busy = false; return resolveValue; } - this.busy = false; + this.filePickBox.busy = false; return undefined; } @@ -504,7 +470,7 @@ export class RemoteFileDialog { } private setAutoComplete(startingValue: string, startingBasename: string, quickPickItem: FileQuickPickItem, force: boolean = false): boolean { - if (this.busy) { + if (this.filePickBox.busy) { // We're in the middle of something else. Doing an auto complete now can result jumbled or incorrect autocompletes. this.userEnteredPathSegment = startingBasename; this.autoCompletePathSegment = ''; @@ -528,6 +494,9 @@ export class RemoteFileDialog { // Changing the active items will trigger the onDidActiveItemsChanged. Clear the autocomplete first, then set it after. this.autoCompletePathSegment = ''; this.filePickBox.activeItems = [quickPickItem]; + this.autoCompletePathSegment = this.trimTrailingSlash(itemBasename.substr(startingBasename.length)); + this.insertText(startingValue + this.autoCompletePathSegment, this.autoCompletePathSegment); + this.filePickBox.valueSelection = [startingValue.length, this.filePickBox.value.length]; return true; } else if (force && (!equalsIgnoreCase(quickPickItem.label, (this.userEnteredPathSegment + this.autoCompletePathSegment)))) { this.userEnteredPathSegment = ''; @@ -672,7 +641,7 @@ export class RemoteFileDialog { } private async updateItems(newFolder: URI, force: boolean = false, trailing?: string) { - this.busy = true; + this.filePickBox.busy = true; this.userEnteredPathSegment = trailing ? trailing : ''; this.autoCompletePathSegment = ''; const newValue = trailing ? this.pathFromUri(resources.joinPath(newFolder, trailing)) : this.pathFromUri(newFolder, true); @@ -694,7 +663,7 @@ export class RemoteFileDialog { // If there is trailing, we don't move the cursor. If there is no trailing, cursor goes at the end. this.filePickBox.valueSelection = [this.filePickBox.value.length, this.filePickBox.value.length]; } - this.busy = false; + this.filePickBox.busy = false; }); } diff --git a/src/vs/workbench/services/editor/browser/editorService.ts b/src/vs/workbench/services/editor/browser/editorService.ts index c46326567e..e7a83af351 100644 --- a/src/vs/workbench/services/editor/browser/editorService.ts +++ b/src/vs/workbench/services/editor/browser/editorService.ts @@ -658,17 +658,18 @@ export class DelegatingEditorService extends EditorService { this.editorOpenHandler = handler; } - protected async doOpenEditor(group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise { + protected doOpenEditor(group: IEditorGroup, editor: IEditorInput, options?: IEditorOptions): Promise { if (!this.editorOpenHandler) { return super.doOpenEditor(group, editor, options); } - const control = await this.editorOpenHandler(group, editor, options); - if (control) { - return control; // the opening was handled, so return early - } + return this.editorOpenHandler(group, editor, options).then(control => { + if (control) { + return control; // the opening was handled, so return early + } - return super.doOpenEditor(group, editor, options); + return super.doOpenEditor(group, editor, options); + }); } } diff --git a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts b/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts index 4755baa5ee..8db1f8421d 100644 --- a/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts +++ b/src/vs/workbench/services/extensionManagement/node/extensionEnablementService.ts @@ -14,9 +14,8 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { isUndefinedOrNull } from 'vs/base/common/types'; import { ExtensionType, IExtension } from 'vs/platform/extensions/common/extensions'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IProductService } from 'vs/platform/product/common/product'; const DISABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/disabled'; const ENABLED_EXTENSIONS_STORAGE_PATH = 'extensionsIdentifiers/enabled'; @@ -37,7 +36,6 @@ export class ExtensionEnablementService extends Disposable implements IExtension @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, @IConfigurationService private readonly configurationService: IConfigurationService, @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, - @IProductService private readonly productService: IProductService, ) { super(); this.storageManger = this._register(new StorageManager(storageService)); @@ -139,7 +137,7 @@ export class ExtensionEnablementService extends Disposable implements IExtension return disabledExtensions.some(id => areSameExtensions({ id }, extension.identifier)); } if (this.environmentService.configuration.remoteAuthority) { - const server = isUIExtension(extension.manifest, this.productService, this.configurationService) ? this.extensionManagementServerService.localExtensionManagementServer : this.extensionManagementServerService.remoteExtensionManagementServer; + const server = isUIExtension(extension.manifest, this.configurationService) ? this.extensionManagementServerService.localExtensionManagementServer : this.extensionManagementServerService.remoteExtensionManagementServer; return this.extensionManagementServerService.getExtensionManagementServer(extension.location) !== server; } return false; diff --git a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts index a35380c732..aa1f950c78 100644 --- a/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts +++ b/src/vs/workbench/services/extensionManagement/test/electron-browser/extensionEnablementService.test.ts @@ -15,7 +15,6 @@ import { IExtensionContributions, ExtensionType, IExtension } from 'vs/platform/ import { isUndefinedOrNull } from 'vs/base/common/types'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { ProductService } from 'vs/platform/product/node/productService'; function storageService(instantiationService: TestInstantiationService): IStorageService { let service = instantiationService.get(IStorageService); @@ -39,9 +38,7 @@ export class TestExtensionEnablementService extends ExtensionEnablementService { instantiationService.get(IWorkbenchEnvironmentService) || instantiationService.stub(IWorkbenchEnvironmentService, { configuration: Object.create(null) } as IWorkbenchEnvironmentService), instantiationService.get(IExtensionManagementService) || instantiationService.stub(IExtensionManagementService, { onDidInstallExtension: new Emitter().event, onDidUninstallExtension: new Emitter().event } as IExtensionManagementService), - instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService), - new ProductService() - ); + instantiationService.get(IConfigurationService), instantiationService.get(IExtensionManagementServerService)); } public reset(): void { diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts deleted file mode 100644 index de1dcd86b5..0000000000 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ /dev/null @@ -1,101 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IFileService } from 'vs/platform/files/common/files'; -import { IProductService } from 'vs/platform/product/common/product'; -import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; -import { browserWebSocketFactory } from 'vs/platform/remote/browser/browserWebSocketFactory'; -import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; -import { RemoteExtensionHostClient, IInitDataProvider } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; -import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; - -export class ExtensionService extends AbstractExtensionService implements IExtensionService { - - private _remoteExtensionsEnvironmentData: IRemoteAgentEnvironment | null; - - constructor( - @IInstantiationService instantiationService: IInstantiationService, - @INotificationService notificationService: INotificationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @ITelemetryService telemetryService: ITelemetryService, - @IExtensionEnablementService extensionEnablementService: IExtensionEnablementService, - @IFileService fileService: IFileService, - @IProductService productService: IProductService, - @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, - ) { - super( - instantiationService, - notificationService, - environmentService, - telemetryService, - extensionEnablementService, - fileService, - productService, - ); - - this._remoteExtensionsEnvironmentData = null; - this._initialize(); - } - - private _createProvider(remoteAuthority: string): IInitDataProvider { - return { - remoteAuthority: remoteAuthority, - getInitData: () => { - return this.whenInstalledExtensionsRegistered().then(() => { - return this._remoteExtensionsEnvironmentData!; - }); - } - }; - } - - protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] { - const result: ExtensionHostProcessManager[] = []; - - const remoteAgentConnection = this._remoteAgentService.getConnection()!; - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), browserWebSocketFactory); - const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); - result.push(remoteExtHostProcessManager); - - return result; - } - - protected async _scanAndHandleExtensions(): Promise { - // fetch the remote environment - const remoteEnv = (await this._remoteAgentService.getEnvironment())!; - - // enable or disable proposed API per extension - this._checkEnableProposedApi(remoteEnv.extensions); - - // remove disabled extensions - remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension)); - - // save for remote extension's init data - this._remoteExtensionsEnvironmentData = remoteEnv; - - // this._handleExtensionPoints(([]).concat(remoteEnv.extensions).concat(localExtensions)); - const result = this._registry.deltaExtensions(remoteEnv.extensions, []); - if (result.removedDueToLooping.length > 0) { - this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); - } - - this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); - } - - public _onExtensionHostExit(code: number): void { - console.log(`vscode:exit`, code); - // ipc.send('vscode:exit', code); - } -} - -registerSingleton(IExtensionService, ExtensionService); diff --git a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts b/src/vs/workbench/services/extensions/common/abstractExtensionService.ts deleted file mode 100644 index 146fc36ea0..0000000000 --- a/src/vs/workbench/services/extensions/common/abstractExtensionService.ts +++ /dev/null @@ -1,498 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { isNonEmptyArray } from 'vs/base/common/arrays'; -import { Barrier } from 'vs/base/common/async'; -import { Emitter, Event } from 'vs/base/common/event'; -import { Disposable } from 'vs/base/common/lifecycle'; -import * as perf from 'vs/base/common/performance'; -import { isEqualOrParent } from 'vs/base/common/resources'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService } from 'vs/platform/extensionManagement/common/extensionManagement'; -import { BetterMergeId } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; -import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; -import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; -import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; -import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions'; -import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; -import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; -import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { IFileService } from 'vs/platform/files/common/files'; -import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; -import { IProductService } from 'vs/platform/product/common/product'; - -const hasOwnProperty = Object.hasOwnProperty; -const NO_OP_VOID_PROMISE = Promise.resolve(undefined); - -export abstract class AbstractExtensionService extends Disposable implements IExtensionService { - - public _serviceBrand: any; - - protected readonly _onDidRegisterExtensions: Emitter = this._register(new Emitter()); - public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event; - - protected readonly _onDidChangeExtensionsStatus: Emitter = this._register(new Emitter()); - public readonly onDidChangeExtensionsStatus: Event = this._onDidChangeExtensionsStatus.event; - - protected readonly _onDidChangeExtensions: Emitter = this._register(new Emitter()); - public readonly onDidChangeExtensions: Event = this._onDidChangeExtensions.event; - - protected readonly _onWillActivateByEvent = this._register(new Emitter()); - public readonly onWillActivateByEvent: Event = this._onWillActivateByEvent.event; - - protected readonly _onDidChangeResponsiveChange = this._register(new Emitter()); - public readonly onDidChangeResponsiveChange: Event = this._onDidChangeResponsiveChange.event; - - protected readonly _registry: ExtensionDescriptionRegistry; - private readonly _installedExtensionsReady: Barrier; - protected readonly _isDev: boolean; - private readonly _extensionsMessages: Map; - protected readonly _allRequestedActivateEvents: { [activationEvent: string]: boolean; }; - private readonly _proposedApiController: ProposedApiController; - private readonly _isExtensionDevHost: boolean; - protected readonly _isExtensionDevTestFromCli: boolean; - - // --- Members used per extension host process - protected _extensionHostProcessManagers: ExtensionHostProcessManager[]; - protected _extensionHostActiveExtensions: Map; - private _extensionHostProcessActivationTimes: Map; - private _extensionHostExtensionRuntimeErrors: Map; - - constructor( - @IInstantiationService protected readonly _instantiationService: IInstantiationService, - @INotificationService protected readonly _notificationService: INotificationService, - @IWorkbenchEnvironmentService protected readonly _environmentService: IWorkbenchEnvironmentService, - @ITelemetryService protected readonly _telemetryService: ITelemetryService, - @IExtensionEnablementService protected readonly _extensionEnablementService: IExtensionEnablementService, - @IFileService protected readonly _fileService: IFileService, - @IProductService protected readonly _productService: IProductService - ) { - super(); - - // help the file service to activate providers by activating extensions by file system event - this._register(this._fileService.onWillActivateFileSystemProvider(e => { - e.join(this.activateByEvent(`onFileSystem:${e.scheme}`)); - })); - - this._registry = new ExtensionDescriptionRegistry([]); - this._installedExtensionsReady = new Barrier(); - this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; - this._extensionsMessages = new Map(); - this._allRequestedActivateEvents = Object.create(null); - this._proposedApiController = new ProposedApiController(this._environmentService, this._productService); - - this._extensionHostProcessManagers = []; - this._extensionHostActiveExtensions = new Map(); - this._extensionHostProcessActivationTimes = new Map(); - this._extensionHostExtensionRuntimeErrors = new Map(); - - const devOpts = parseExtensionDevOptions(this._environmentService); - this._isExtensionDevHost = devOpts.isExtensionDevHost; - this._isExtensionDevTestFromCli = devOpts.isExtensionDevTestFromCli; - } - - protected async _initialize(): Promise { - perf.mark('willLoadExtensions'); - this._startExtensionHostProcess(true, []); - this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions')); - await this._scanAndHandleExtensions(); - this._releaseBarrier(); - } - - private _releaseBarrier(): void { - perf.mark('extensionHostReady'); - this._installedExtensionsReady.open(); - this._onDidRegisterExtensions.fire(undefined); - this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier)); - } - - private _stopExtensionHostProcess(): void { - let previouslyActivatedExtensionIds: ExtensionIdentifier[] = []; - this._extensionHostActiveExtensions.forEach((value) => { - previouslyActivatedExtensionIds.push(value); - }); - - for (const manager of this._extensionHostProcessManagers) { - manager.dispose(); - } - this._extensionHostProcessManagers = []; - this._extensionHostActiveExtensions = new Map(); - this._extensionHostProcessActivationTimes = new Map(); - this._extensionHostExtensionRuntimeErrors = new Map(); - - if (previouslyActivatedExtensionIds.length > 0) { - this._onDidChangeExtensionsStatus.fire(previouslyActivatedExtensionIds); - } - } - - private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void { - this._stopExtensionHostProcess(); - - const processManagers = this._createExtensionHosts(isInitialStart, initialActivationEvents); - processManagers.forEach((processManager) => { - processManager.onDidExit(([code, signal]) => this._onExtensionHostCrashOrExit(processManager, code, signal)); - processManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); }); - this._extensionHostProcessManagers.push(processManager); - }); - } - - private _onExtensionHostCrashOrExit(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { - - // Unexpected termination - if (!this._isExtensionDevHost) { - this._onExtensionHostCrashed(extensionHost, code, signal); - return; - } - - this._onExtensionHostExit(code); - } - - protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { - console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal); - this._stopExtensionHostProcess(); - } - - //#region IExtensionService - - public canAddExtension(extension: IExtensionDescription): boolean { - return false; - } - - public canRemoveExtension(extension: IExtensionDescription): boolean { - return false; - } - - public restartExtensionHost(): void { - this._stopExtensionHostProcess(); - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); - } - - public startExtensionHost(): void { - this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); - } - - public stopExtensionHost(): void { - this._stopExtensionHostProcess(); - } - - public activateByEvent(activationEvent: string): Promise { - if (this._installedExtensionsReady.isOpen()) { - // Extensions have been scanned and interpreted - - // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; - - if (!this._registry.containsActivationEvent(activationEvent)) { - // There is no extension that is interested in this activation event - return NO_OP_VOID_PROMISE; - } - - return this._activateByEvent(activationEvent); - } else { - // Extensions have not been scanned yet. - - // Record the fact that this activationEvent was requested (in case of a restart) - this._allRequestedActivateEvents[activationEvent] = true; - - return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent)); - } - } - - private _activateByEvent(activationEvent: string): Promise { - const result = Promise.all( - this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent)) - ).then(() => { }); - this._onWillActivateByEvent.fire({ - event: activationEvent, - activation: result - }); - return result; - } - - public whenInstalledExtensionsRegistered(): Promise { - return this._installedExtensionsReady.wait(); - } - - public getExtensions(): Promise { - return this._installedExtensionsReady.wait().then(() => { - return this._registry.getAllExtensionDescriptions(); - }); - } - - public getExtension(id: string): Promise { - return this._installedExtensionsReady.wait().then(() => { - return this._registry.getExtensionDescription(id); - }); - } - - public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { - return this._installedExtensionsReady.wait().then(() => { - let availableExtensions = this._registry.getAllExtensionDescriptions(); - - let result: ExtensionPointContribution[] = [], resultLen = 0; - for (let i = 0, len = availableExtensions.length; i < len; i++) { - let desc = availableExtensions[i]; - - if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) { - result[resultLen++] = new ExtensionPointContribution(desc, desc.contributes[extPoint.name]); - } - } - - return result; - }); - } - - public getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { - let result: { [id: string]: IExtensionsStatus; } = Object.create(null); - if (this._registry) { - const extensions = this._registry.getAllExtensionDescriptions(); - for (const extension of extensions) { - const extensionKey = ExtensionIdentifier.toKey(extension.identifier); - result[extension.identifier.value] = { - messages: this._extensionsMessages.get(extensionKey) || [], - activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey), - runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [], - }; - } - } - return result; - } - - public getInspectPort(): number { - return 0; - } - - //#endregion - - // --- impl - - protected _checkEnableProposedApi(extensions: IExtensionDescription[]): void { - for (let extension of extensions) { - this._proposedApiController.updateEnableProposedApi(extension); - } - } - - private _isExtensionUnderDevelopment(extension: IExtensionDescription): boolean { - if (this._environmentService.isExtensionDevelopment) { - const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; - if (extDevLocs) { - const extLocation = extension.extensionLocation; - for (let p of extDevLocs) { - if (isEqualOrParent(extLocation, p)) { - return true; - } - } - } - } - return false; - } - - protected _isEnabled(extension: IExtensionDescription): boolean { - if (this._isExtensionUnderDevelopment(extension)) { - // Never disable extensions under development - return true; - } - - if (ExtensionIdentifier.equals(extension.identifier, BetterMergeId)) { - // Check if this is the better merge extension which was migrated to a built-in extension - return false; - } - - return this._extensionEnablementService.isEnabled(toExtension(extension)); - } - - protected _doHandleExtensionPoints(affectedExtensions: IExtensionDescription[]): void { - const affectedExtensionPoints: { [extPointName: string]: boolean; } = Object.create(null); - for (let extensionDescription of affectedExtensions) { - if (extensionDescription.contributes) { - for (let extPointName in extensionDescription.contributes) { - if (hasOwnProperty.call(extensionDescription.contributes, extPointName)) { - affectedExtensionPoints[extPointName] = true; - } - } - } - } - - const messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); - const availableExtensions = this._registry.getAllExtensionDescriptions(); - const extensionPoints = ExtensionsRegistry.getExtensionPoints(); - for (let i = 0, len = extensionPoints.length; i < len; i++) { - if (affectedExtensionPoints[extensionPoints[i].name]) { - AbstractExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); - } - } - } - - private _handleExtensionPointMessage(msg: IMessage) { - const extensionKey = ExtensionIdentifier.toKey(msg.extensionId); - - if (!this._extensionsMessages.has(extensionKey)) { - this._extensionsMessages.set(extensionKey, []); - } - this._extensionsMessages.get(extensionKey)!.push(msg); - - const extension = this._registry.getExtensionDescription(msg.extensionId); - const strMsg = `[${msg.extensionId.value}]: ${msg.message}`; - if (extension && extension.isUnderDevelopment) { - // This message is about the extension currently being developed - this._showMessageToUser(msg.type, strMsg); - } else { - this._logMessageInConsole(msg.type, strMsg); - } - - if (!this._isDev && msg.extensionId) { - const { type, extensionId, extensionPointId, message } = msg; - /* __GDPR__ - "extensionsMessage" : { - "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, - "extensionId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "extensionPointId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, - "message": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this._telemetryService.publicLog('extensionsMessage', { - type, extensionId: extensionId.value, extensionPointId, message - }); - } - } - - private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { - let users: IExtensionPointUser[] = [], usersLen = 0; - for (let i = 0, len = availableExtensions.length; i < len; i++) { - let desc = availableExtensions[i]; - - if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) { - users[usersLen++] = { - description: desc, - value: desc.contributes[extensionPoint.name], - collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name) - }; - } - } - - extensionPoint.acceptUsers(users); - } - - private _showMessageToUser(severity: Severity, msg: string): void { - if (severity === Severity.Error || severity === Severity.Warning) { - this._notificationService.notify({ severity, message: msg }); - } else { - this._logMessageInConsole(severity, msg); - } - } - - private _logMessageInConsole(severity: Severity, msg: string): void { - if (severity === Severity.Error) { - console.error(msg); - } else if (severity === Severity.Warning) { - console.warn(msg); - } else { - console.log(msg); - } - } - - //#region Called by extension host - - public _logOrShowMessage(severity: Severity, msg: string): void { - if (this._isDev) { - this._showMessageToUser(severity, msg); - } else { - this._logMessageInConsole(severity, msg); - } - } - - public async _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise { - const results = await Promise.all( - this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, activationEvent)) - ); - const activated = results.some(e => e); - if (!activated) { - throw new Error(`Unknown extension ${extensionId.value}`); - } - } - - public _onWillActivateExtension(extensionId: ExtensionIdentifier): void { - this._extensionHostActiveExtensions.set(ExtensionIdentifier.toKey(extensionId), extensionId); - } - - public _onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void { - this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent)); - this._onDidChangeExtensionsStatus.fire([extensionId]); - } - - public _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void { - const extensionKey = ExtensionIdentifier.toKey(extensionId); - if (!this._extensionHostExtensionRuntimeErrors.has(extensionKey)) { - this._extensionHostExtensionRuntimeErrors.set(extensionKey, []); - } - this._extensionHostExtensionRuntimeErrors.get(extensionKey)!.push(err); - this._onDidChangeExtensionsStatus.fire([extensionId]); - } - - //#endregion - - protected abstract _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[]; - protected abstract _scanAndHandleExtensions(): Promise; - public abstract _onExtensionHostExit(code: number): void; -} - -class ProposedApiController { - - private readonly enableProposedApiFor: string | string[]; - private readonly enableProposedApiForAll: boolean; - private readonly productAllowProposedApi: Set; - - constructor( - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @IProductService productService: IProductService - ) { - this.enableProposedApiFor = environmentService.args['enable-proposed-api'] || []; - if (this.enableProposedApiFor.length) { - // Make enabled proposed API be lowercase for case insensitive comparison - if (Array.isArray(this.enableProposedApiFor)) { - this.enableProposedApiFor = this.enableProposedApiFor.map(id => id.toLowerCase()); - } else { - this.enableProposedApiFor = this.enableProposedApiFor.toLowerCase(); - } - } - - this.enableProposedApiForAll = !environmentService.isBuilt || - (!!environmentService.extensionDevelopmentLocationURI && productService.nameLong !== 'Visual Studio Code') || - (this.enableProposedApiFor.length === 0 && 'enable-proposed-api' in environmentService.args); - - this.productAllowProposedApi = new Set(); - if (isNonEmptyArray(productService.extensionAllowedProposedApi)) { - productService.extensionAllowedProposedApi.forEach((id) => this.productAllowProposedApi.add(ExtensionIdentifier.toKey(id))); - } - } - - public updateEnableProposedApi(extension: IExtensionDescription): void { - if (this._allowProposedApiFromProduct(extension.identifier)) { - // fast lane -> proposed api is available to all extensions - // that are listed in product.json-files - extension.enableProposedApi = true; - - } else if (extension.enableProposedApi && !extension.isBuiltin) { - if ( - !this.enableProposedApiForAll && - this.enableProposedApiFor.indexOf(extension.identifier.value.toLowerCase()) < 0 - ) { - extension.enableProposedApi = false; - console.error(`Extension '${extension.identifier.value} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`); - - } else { - // proposed api is available when developing or when an extension was explicitly - // spelled out via a command line argument - console.warn(`Extension '${extension.identifier.value}' uses PROPOSED API which is subject to change and removal without notice.`); - } - } - } - - private _allowProposedApiFromProduct(id: ExtensionIdentifier): boolean { - return this.productAllowProposedApi.has(ExtensionIdentifier.toKey(id)); - } -} diff --git a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts index 262e4e3dcd..33f1773a81 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProcessManager.ts @@ -35,7 +35,7 @@ const NO_OP_VOID_PROMISE = Promise.resolve(undefined); export class ExtensionHostProcessManager extends Disposable { - public readonly onDidExit: Event<[number, string | null]>; + public readonly onDidCrash: Event<[number, string | null]>; private readonly _onDidChangeResponsiveState: Emitter = this._register(new Emitter()); public readonly onDidChangeResponsiveState: Event = this._onDidChangeResponsiveState.event; @@ -54,7 +54,6 @@ export class ExtensionHostProcessManager extends Disposable { private _resolveAuthorityAttempt: number; constructor( - public readonly isLocal: boolean, extensionHostProcessWorker: IExtensionHostStarter, private readonly _remoteAuthority: string, initialActivationEvents: string[], @@ -67,7 +66,7 @@ export class ExtensionHostProcessManager extends Disposable { this._extensionHostProcessCustomers = []; this._extensionHostProcessWorker = extensionHostProcessWorker; - this.onDidExit = this._extensionHostProcessWorker.onExit; + this.onDidCrash = this._extensionHostProcessWorker.onCrashed; this._extensionHostProcessProxy = this._extensionHostProcessWorker.start()!.then( (protocol) => { return { value: this._createExtensionHostCustomers(protocol) }; diff --git a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts index b06566e887..663d522d83 100644 --- a/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts +++ b/src/vs/workbench/services/extensions/common/extensionHostProtocol.ts @@ -12,7 +12,6 @@ export interface IExtHostReadyMessage { export interface IExtHostSocketMessage { type: 'VSCODE_EXTHOST_IPC_SOCKET'; initialDataChunk: string; - skipWebSocketFrames: boolean; } export const enum MessageType { diff --git a/src/vs/workbench/services/extensions/common/extensionPoints.ts b/src/vs/workbench/services/extensions/common/extensionPoints.ts deleted file mode 100644 index f5291468d2..0000000000 --- a/src/vs/workbench/services/extensions/common/extensionPoints.ts +++ /dev/null @@ -1,63 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Severity } from 'vs/platform/notification/common/notification'; - -export interface Translations { - [id: string]: string; -} - -export namespace Translations { - export function equals(a: Translations, b: Translations): boolean { - if (a === b) { - return true; - } - let aKeys = Object.keys(a); - let bKeys: Set = new Set(); - for (let key of Object.keys(b)) { - bKeys.add(key); - } - if (aKeys.length !== bKeys.size) { - return false; - } - - for (let key of aKeys) { - if (a[key] !== b[key]) { - return false; - } - bKeys.delete(key); - } - return bKeys.size === 0; - } -} - -export interface ILog { - error(source: string, message: string): void; - warn(source: string, message: string): void; - info(source: string, message: string): void; -} - -export class Logger implements ILog { - - private readonly _messageHandler: (severity: Severity, source: string, message: string) => void; - - constructor( - messageHandler: (severity: Severity, source: string, message: string) => void - ) { - this._messageHandler = messageHandler; - } - - public error(source: string, message: string): void { - this._messageHandler(Severity.Error, source, message); - } - - public warn(source: string, message: string): void { - this._messageHandler(Severity.Warning, source, message); - } - - public info(source: string, message: string): void { - this._messageHandler(Severity.Info, source, message); - } -} diff --git a/src/vs/workbench/services/extensions/common/extensions.ts b/src/vs/workbench/services/extensions/common/extensions.ts index 3f66df503d..a234d6c846 100644 --- a/src/vs/workbench/services/extensions/common/extensions.ts +++ b/src/vs/workbench/services/extensions/common/extensions.ts @@ -84,8 +84,7 @@ export interface IExtensionHostProfile { } export interface IExtensionHostStarter { - readonly onExit: Event<[number, string | null]>; - + readonly onCrashed: Event<[number, string | null]>; start(): Promise | null; getInspectPort(): number | undefined; dispose(): void; diff --git a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts index 4bd6481521..f38eb6b508 100644 --- a/src/vs/workbench/services/extensions/common/extensionsRegistry.ts +++ b/src/vs/workbench/services/extensions/common/extensionsRegistry.ts @@ -341,19 +341,6 @@ export const schema = { pattern: EXTENSION_IDENTIFIER_PATTERN } }, - extensionKind: { - description: nls.localize('extensionKind', "Define the kind of an extension. `ui` extensions are installed and run on the local machine while `workspace` extensions are run on the remote."), - type: 'string', - enum: [ - 'ui', - 'workspace' - ], - enumDescriptions: [ - nls.localize('ui', "UI extension kind. In a remote window, such extensions are enabled only when available on the local machine."), - nls.localize('workspace', "Workspace extension kind. In a remote window, such extensions are enabled only when available on the remote.") - ], - default: 'workspace' - }, scripts: { type: 'object', properties: { diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index e82f6fb6bf..1dc53d5a8e 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -5,7 +5,7 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; -import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; +import { IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { EnablementState, IExtensionEnablementService, IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; @@ -70,10 +70,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.handleURL(URI.revive(JSON.parse(urlToHandleValue)), true); } - this.disposable = combinedDisposable( + this.disposable = combinedDisposable([ urlService.registerHandler(this), toDisposable(() => clearInterval(interval)) - ); + ]); } async handleURL(uri: URI, confirmed?: boolean): Promise { diff --git a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts index b82afa42ad..399a45d821 100644 --- a/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts +++ b/src/vs/workbench/services/extensions/electron-browser/cachedExtensionScanner.ts @@ -21,8 +21,7 @@ import pkg from 'vs/platform/product/node/package'; import product from 'vs/platform/product/node/product'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { IWindowService } from 'vs/platform/windows/common/windows'; -import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, IRelaxedExtensionDescription } from 'vs/workbench/services/extensions/node/extensionPoints'; -import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; +import { ExtensionScanner, ExtensionScannerInput, IExtensionReference, IExtensionResolver, ILog, IRelaxedExtensionDescription, Translations } from 'vs/workbench/services/extensions/node/extensionPoints'; interface IExtensionCacheData { input: ExtensionScannerInput; @@ -388,3 +387,26 @@ class NullLogger implements ILog { public info(source: string, message: string): void { } } + +export class Logger implements ILog { + + private readonly _messageHandler: (severity: Severity, source: string, message: string) => void; + + constructor( + messageHandler: (severity: Severity, source: string, message: string) => void + ) { + this._messageHandler = messageHandler; + } + + public error(source: string, message: string): void { + this._messageHandler(Severity.Error, source, message); + } + + public warn(source: string, message: string): void { + this._messageHandler(Severity.Warning, source, message); + } + + public info(source: string, message: string): void { + this._messageHandler(Severity.Info, source, message); + } +} diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts index b735a0247f..60355932d6 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionHost.ts @@ -5,12 +5,13 @@ import * as nls from 'vs/nls'; import { ChildProcess, fork } from 'child_process'; +import { ipcRenderer as ipc } from 'electron'; import { Server, Socket, createServer } from 'net'; import { getPathFromAmdModule } from 'vs/base/common/amd'; import { timeout } from 'vs/base/common/async'; import { toErrorMessage } from 'vs/base/common/errorMessage'; import { Emitter, Event } from 'vs/base/common/event'; -import { toDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, toDisposable } from 'vs/base/common/lifecycle'; import * as objects from 'vs/base/common/objects'; import * as platform from 'vs/base/common/platform'; import pkg from 'vs/platform/product/node/package'; @@ -41,10 +42,10 @@ import { isEqualOrParent } from 'vs/base/common/resources'; export class ExtensionHostProcessWorker implements IExtensionHostStarter { - private readonly _onExit: Emitter<[number, string]> = new Emitter<[number, string]>(); - public readonly onExit: Event<[number, string]> = this._onExit.event; + private readonly _onCrashed: Emitter<[number, string]> = new Emitter<[number, string]>(); + public readonly onCrashed: Event<[number, string]> = this._onCrashed.event; - private readonly _toDispose = new DisposableStore(); + private readonly _toDispose: IDisposable[]; private readonly _isExtensionDevHost: boolean; private readonly _isExtensionDevDebug: boolean; @@ -91,15 +92,16 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { this._extensionHostConnection = null; this._messageProtocol = null; - this._toDispose.add(this._onExit); - this._toDispose.add(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); - this._toDispose.add(this._lifecycleService.onShutdown(reason => this.terminate())); - this._toDispose.add(this._extensionHostDebugService.onClose(event => { + this._toDispose = []; + this._toDispose.push(this._onCrashed); + this._toDispose.push(this._lifecycleService.onWillShutdown(e => this._onWillShutdown(e))); + this._toDispose.push(this._lifecycleService.onShutdown(reason => this.terminate())); + this._toDispose.push(this._extensionHostDebugService.onClose(event => { if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.closeWindow(); } })); - this._toDispose.add(this._extensionHostDebugService.onReload(event => { + this._toDispose.push(this._extensionHostDebugService.onReload(event => { if (this._isExtensionDevHost && this._environmentService.debugExtensionHost.debugId === event.sessionId) { this._windowService.reloadWindow(); } @@ -107,7 +109,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { const globalExitListener = () => this.terminate(); process.once('exit', globalExitListener); - this._toDispose.add(toDisposable(() => { + this._toDispose.push(toDisposable(() => { process.removeListener('exit', globalExitListener); })); } @@ -449,7 +451,20 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { return; } - this._onExit.fire([code, signal]); + // Unexpected termination + if (!this._isExtensionDevHost) { + this._onCrashed.fire([code, signal]); + } + + // Expected development extension termination: When the extension host goes down we also shutdown the window + else if (!this._isExtensionDevTestFromCli) { + this._windowService.closeWindow(); + } + + // When CLI testing make sure to exit with proper exit code + else { + ipc.send('vscode:exit', code); + } } public enableInspector(): Promise { @@ -474,7 +489,7 @@ export class ExtensionHostProcessWorker implements IExtensionHostStarter { } this._terminating = true; - this._toDispose.dispose(); + dispose(this._toDispose); if (!this._messageProtocol) { // .start() was not called diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index aee8233572..fe3aa6314c 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -3,37 +3,62 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { ipcRenderer as ipc } from 'electron'; -import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; -import { CachedExtensionScanner } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; -import { AbstractExtensionService } from 'vs/workbench/services/extensions/common/abstractExtensionService'; import * as nls from 'vs/nls'; import * as path from 'vs/base/common/path'; -import { runWhenIdle } from 'vs/base/common/async'; +import { ipcRenderer as ipc } from 'electron'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; +import { Barrier, runWhenIdle } from 'vs/base/common/async'; +import { Emitter, Event } from 'vs/base/common/event'; +import { Disposable } from 'vs/base/common/lifecycle'; +import * as perf from 'vs/base/common/performance'; +import { isEqualOrParent } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IExtensionEnablementService, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { EnablementState, IExtensionEnablementService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; +import { BetterMergeId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/common/remoteExtensionHostClient'; +import { IInitDataProvider, RemoteExtensionHostClient } from 'vs/workbench/services/extensions/electron-browser/remoteExtensionHostClient'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService, ResolvedAuthority, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; import { IRemoteAgentEnvironment } from 'vs/platform/remote/common/remoteAgentEnvironment'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ILifecycleService, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; +import pkg from 'vs/platform/product/node/package'; +import product from 'vs/platform/product/node/product'; import { INotificationService, Severity } from 'vs/platform/notification/common/notification'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; -import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; +import { ActivationTimes, ExtensionPointContribution, IExtensionService, IExtensionsStatus, IMessage, IWillActivateEvent, IResponsiveStateChangeEvent, toExtension } from 'vs/workbench/services/extensions/common/extensions'; +import { ExtensionMessageCollector, ExtensionPoint, ExtensionsRegistry, IExtensionPoint, IExtensionPointUser, schema } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { ExtensionHostProcessWorker } from 'vs/workbench/services/extensions/electron-browser/extensionHost'; +import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; +import { ResponsiveState } from 'vs/workbench/services/extensions/common/rpcProtocol'; +import { CachedExtensionScanner, Logger } from 'vs/workbench/services/extensions/electron-browser/cachedExtensionScanner'; import { ExtensionHostProcessManager } from 'vs/workbench/services/extensions/common/extensionHostProcessManager'; import { ExtensionIdentifier, IExtension, ExtensionType, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Schemas } from 'vs/base/common/network'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { IFileService } from 'vs/platform/files/common/files'; +import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions'; import { PersistenConnectionEventType } from 'vs/platform/remote/common/remoteAgentConnection'; -import { IProductService } from 'vs/platform/product/common/product'; -import { Logger } from 'vs/workbench/services/extensions/common/extensionPoints'; + +const hasOwnProperty = Object.hasOwnProperty; +const NO_OP_VOID_PROMISE = Promise.resolve(undefined); + +schema.properties.engines.properties.vscode.default = `^${pkg.version}`; + +let productAllowProposedApi: Set | null = null; +function allowProposedApiFromProduct(id: ExtensionIdentifier): boolean { + // create set if needed + if (!productAllowProposedApi) { + productAllowProposedApi = new Set(); + if (isNonEmptyArray(product.extensionAllowedProposedApi)) { + product.extensionAllowedProposedApi.forEach((id) => productAllowProposedApi!.add(ExtensionIdentifier.toKey(id))); + } + } + return productAllowProposedApi.has(ExtensionIdentifier.toKey(id)); +} class DeltaExtensionsQueueItem { constructor( @@ -42,38 +67,80 @@ class DeltaExtensionsQueueItem { ) { } } -export class ExtensionService extends AbstractExtensionService implements IExtensionService { +export class ExtensionService extends Disposable implements IExtensionService { - private readonly _remoteExtensionsEnvironmentData: Map; + public _serviceBrand: any; + + private _remoteExtensionsEnvironmentData: Map; private readonly _extensionHostLogsLocation: URI; + private readonly _registry: ExtensionDescriptionRegistry; + private readonly _installedExtensionsReady: Barrier; + private readonly _isDev: boolean; + private readonly _extensionsMessages: Map; + private _allRequestedActivateEvents: { [activationEvent: string]: boolean; }; private readonly _extensionScanner: CachedExtensionScanner; private _deltaExtensionsQueue: DeltaExtensionsQueueItem[]; + private readonly _onDidRegisterExtensions: Emitter = this._register(new Emitter()); + public readonly onDidRegisterExtensions = this._onDidRegisterExtensions.event; + + private readonly _onDidChangeExtensionsStatus: Emitter = this._register(new Emitter()); + public readonly onDidChangeExtensionsStatus: Event = this._onDidChangeExtensionsStatus.event; + + private readonly _onDidChangeExtensions: Emitter = this._register(new Emitter()); + public readonly onDidChangeExtensions: Event = this._onDidChangeExtensions.event; + + private readonly _onWillActivateByEvent = this._register(new Emitter()); + public readonly onWillActivateByEvent: Event = this._onWillActivateByEvent.event; + + private readonly _onDidChangeResponsiveChange = this._register(new Emitter()); + public readonly onDidChangeResponsiveChange: Event = this._onDidChangeResponsiveChange.event; + + // --- Members used per extension host process + private _extensionHostProcessManagers: ExtensionHostProcessManager[]; + private _extensionHostActiveExtensions: Map; + private _extensionHostProcessActivationTimes: Map; + private _extensionHostExtensionRuntimeErrors: Map; + constructor( - @IInstantiationService instantiationService: IInstantiationService, - @INotificationService notificationService: INotificationService, - @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, - @ITelemetryService telemetryService: ITelemetryService, - @IExtensionEnablementService extensionEnablementService: IExtensionEnablementService, - @IFileService fileService: IFileService, - @IProductService productService: IProductService, + @IInstantiationService private readonly _instantiationService: IInstantiationService, + @INotificationService private readonly _notificationService: INotificationService, + @IWorkbenchEnvironmentService private readonly _environmentService: IWorkbenchEnvironmentService, + @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IExtensionEnablementService private readonly _extensionEnablementService: IExtensionEnablementService, @IExtensionManagementService private readonly _extensionManagementService: IExtensionManagementService, + @IWindowService private readonly _windowService: IWindowService, @IRemoteAgentService private readonly _remoteAgentService: IRemoteAgentService, @IRemoteAuthorityResolverService private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, @IConfigurationService private readonly _configurationService: IConfigurationService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, - @IWindowService protected readonly _windowService: IWindowService, + @IFileService fileService: IFileService ) { - super( - instantiationService, - notificationService, - environmentService, - telemetryService, - extensionEnablementService, - fileService, - productService, - ); + super(); + + // help the file service to activate providers by activating extensions by file system event + this._register(fileService.onWillActivateFileSystemProvider(e => { + e.join(this.activateByEvent(`onFileSystem:${e.scheme}`)); + })); + + this._remoteExtensionsEnvironmentData = new Map(); + + this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${_windowService.windowId}`)); + this._registry = new ExtensionDescriptionRegistry([]); + this._installedExtensionsReady = new Barrier(); + this._isDev = !this._environmentService.isBuilt || this._environmentService.isExtensionDevelopment; + this._extensionsMessages = new Map(); + this._allRequestedActivateEvents = Object.create(null); + this._extensionScanner = this._instantiationService.createInstance(CachedExtensionScanner); + this._deltaExtensionsQueue = []; + + this._extensionHostProcessManagers = []; + this._extensionHostActiveExtensions = new Map(); + this._extensionHostProcessActivationTimes = new Map(); + this._extensionHostExtensionRuntimeErrors = new Map(); + + this._startDelayed(this._lifecycleService); if (this._extensionEnablementService.allUserExtensionsDisabled) { this._notificationService.prompt(Severity.Info, nls.localize('extensionsDisabled', "All installed extensions are temporarily disabled. Reload the window to return to the previous state."), [{ @@ -84,12 +151,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten }]); } - this._remoteExtensionsEnvironmentData = new Map(); - - this._extensionHostLogsLocation = URI.file(path.join(this._environmentService.logsPath, `exthost${this._windowService.windowId}`)); - this._extensionScanner = instantiationService.createInstance(CachedExtensionScanner); - this._deltaExtensionsQueue = []; - this._register(this._extensionEnablementService.onEnablementChanged((extensions) => { let toAdd: IExtension[] = []; let toRemove: string[] = []; @@ -120,24 +181,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._handleDeltaExtensions(new DeltaExtensionsQueueItem([], [event.identifier.id])); } })); - - // delay extension host creation and extension scanning - // until the workbench is running. we cannot defer the - // extension host more (LifecyclePhase.Restored) because - // some editors require the extension host to restore - // and this would result in a deadlock - // see https://github.com/Microsoft/vscode/issues/41322 - this._lifecycleService.when(LifecyclePhase.Ready).then(() => { - // reschedule to ensure this runs after restoring viewlets, panels, and editors - runWhenIdle(() => { - this._initialize(); - }, 50 /*max delay*/); - }); } - - //#region deltaExtensions - private _inHandleDeltaExtensions = false; private async _handleDeltaExtensions(item: DeltaExtensionsQueueItem): Promise { this._deltaExtensionsQueue.push(item); @@ -229,7 +274,26 @@ export class ExtensionService extends AbstractExtensionService implements IExten } private _rehandleExtensionPoints(extensionDescriptions: IExtensionDescription[]): void { - this._doHandleExtensionPoints(extensionDescriptions); + const affectedExtensionPoints: { [extPointName: string]: boolean; } = Object.create(null); + for (let extensionDescription of extensionDescriptions) { + if (extensionDescription.contributes) { + for (let extPointName in extensionDescription.contributes) { + if (hasOwnProperty.call(extensionDescription.contributes, extPointName)) { + affectedExtensionPoints[extPointName] = true; + } + } + } + } + + const messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); + + const availableExtensions = this._registry.getAllExtensionDescriptions(); + const extensionPoints = ExtensionsRegistry.getExtensionPoints(); + for (let i = 0, len = extensionPoints.length; i < len; i++) { + if (affectedExtensionPoints[extensionPoints[i].name]) { + ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + } + } } public canAddExtension(extension: IExtensionDescription): boolean { @@ -319,20 +383,76 @@ export class ExtensionService extends AbstractExtensionService implements IExten } } - //#endregion + private _startDelayed(lifecycleService: ILifecycleService): void { + // delay extension host creation and extension scanning + // until the workbench is running. we cannot defer the + // extension host more (LifecyclePhase.Restored) because + // some editors require the extension host to restore + // and this would result in a deadlock + // see https://github.com/Microsoft/vscode/issues/41322 + lifecycleService.when(LifecyclePhase.Ready).then(() => { + // reschedule to ensure this runs after restoring viewlets, panels, and editors + runWhenIdle(() => { + perf.mark('willLoadExtensions'); + this._startExtensionHostProcess(true, []); + this._scanAndHandleExtensions(); + this.whenInstalledExtensionsRegistered().then(() => perf.mark('didLoadExtensions')); + }, 50 /*max delay*/); + }); + } + + public dispose(): void { + super.dispose(); + this._onWillActivateByEvent.dispose(); + this._onDidChangeResponsiveChange.dispose(); + } + + public restartExtensionHost(): void { + this._stopExtensionHostProcess(); + this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); + } + + public startExtensionHost(): void { + this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)); + } + + public stopExtensionHost(): void { + this._stopExtensionHostProcess(); + } + + private _stopExtensionHostProcess(): void { + let previouslyActivatedExtensionIds: ExtensionIdentifier[] = []; + this._extensionHostActiveExtensions.forEach((value) => { + previouslyActivatedExtensionIds.push(value); + }); + + for (const manager of this._extensionHostProcessManagers) { + manager.dispose(); + } + this._extensionHostProcessManagers = []; + this._extensionHostActiveExtensions = new Map(); + this._extensionHostProcessActivationTimes = new Map(); + this._extensionHostExtensionRuntimeErrors = new Map(); + + if (previouslyActivatedExtensionIds.length > 0) { + this._onDidChangeExtensionsStatus.fire(previouslyActivatedExtensionIds); + } + } private _createProvider(remoteAuthority: string): IInitDataProvider { return { remoteAuthority: remoteAuthority, getInitData: () => { - return this.whenInstalledExtensionsRegistered().then(() => { + return this._installedExtensionsReady.wait().then(() => { return this._remoteExtensionsEnvironmentData.get(remoteAuthority)!; }); } }; } - protected _createExtensionHosts(isInitialStart: boolean, initialActivationEvents: string[]): ExtensionHostProcessManager[] { + private _startExtensionHostProcess(isInitialStart: boolean, initialActivationEvents: string[]): void { + this._stopExtensionHostProcess(); + let autoStart: boolean; let extensions: Promise; if (isInitialStart) { @@ -344,25 +464,27 @@ export class ExtensionService extends AbstractExtensionService implements IExten extensions = this.getExtensions().then((extensions) => extensions.filter(ext => ext.extensionLocation.scheme === Schemas.file)); } - const result: ExtensionHostProcessManager[] = []; const extHostProcessWorker = this._instantiationService.createInstance(ExtensionHostProcessWorker, autoStart, extensions, this._extensionHostLogsLocation); - const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, true, extHostProcessWorker, null, initialActivationEvents); - result.push(extHostProcessManager); + const extHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, extHostProcessWorker, null, initialActivationEvents); + extHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal, true)); + extHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); }); + this._extensionHostProcessManagers.push(extHostProcessManager); const remoteAgentConnection = this._remoteAgentService.getConnection(); if (remoteAgentConnection) { - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), nodeWebSocketFactory); - const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); - result.push(remoteExtHostProcessManager); + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority)); + const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); + remoteExtHostProcessManager.onDidCrash(([code, signal]) => this._onExtensionHostCrashed(code, signal, false)); + remoteExtHostProcessManager.onDidChangeResponsiveState((responsiveState) => { this._onDidChangeResponsiveChange.fire({ isResponsive: responsiveState === ResponsiveState.Responsive }); }); + this._extensionHostProcessManagers.push(remoteExtHostProcessManager); } - - return result; } - protected _onExtensionHostCrashed(extensionHost: ExtensionHostProcessManager, code: number, signal: string | null): void { - super._onExtensionHostCrashed(extensionHost, code, signal); + private _onExtensionHostCrashed(code: number, signal: string | null, showNotification: boolean): void { + console.error('Extension host terminated unexpectedly. Code: ', code, ' Signal: ', signal); + this._stopExtensionHostProcess(); - if (extensionHost.isLocal) { + if (showNotification) { if (code === 55) { this._notificationService.prompt( Severity.Error, @@ -380,19 +502,118 @@ export class ExtensionService extends AbstractExtensionService implements IExten return; } - this._notificationService.prompt(Severity.Error, nls.localize('extensionService.crash', "Extension host terminated unexpectedly."), + let message = nls.localize('extensionService.crash', "Extension host terminated unexpectedly."); + if (code === 87) { + message = nls.localize('extensionService.unresponsiveCrash', "Extension host terminated because it was not responsive."); + } + + this._notificationService.prompt(Severity.Error, message, [{ label: nls.localize('devTools', "Open Developer Tools"), run: () => this._windowService.openDevTools() }, { label: nls.localize('restart', "Restart Extension Host"), - run: () => this.startExtensionHost() + run: () => this._startExtensionHostProcess(false, Object.keys(this._allRequestedActivateEvents)) }] ); } } + // ---- begin IExtensionService + + public activateByEvent(activationEvent: string): Promise { + if (this._installedExtensionsReady.isOpen()) { + // Extensions have been scanned and interpreted + + // Record the fact that this activationEvent was requested (in case of a restart) + this._allRequestedActivateEvents[activationEvent] = true; + + if (!this._registry.containsActivationEvent(activationEvent)) { + // There is no extension that is interested in this activation event + return NO_OP_VOID_PROMISE; + } + + return this._activateByEvent(activationEvent); + } else { + // Extensions have not been scanned yet. + + // Record the fact that this activationEvent was requested (in case of a restart) + this._allRequestedActivateEvents[activationEvent] = true; + + return this._installedExtensionsReady.wait().then(() => this._activateByEvent(activationEvent)); + } + } + + private _activateByEvent(activationEvent: string): Promise { + const result = Promise.all( + this._extensionHostProcessManagers.map(extHostManager => extHostManager.activateByEvent(activationEvent)) + ).then(() => { }); + this._onWillActivateByEvent.fire({ + event: activationEvent, + activation: result + }); + return result; + } + + public whenInstalledExtensionsRegistered(): Promise { + return this._installedExtensionsReady.wait(); + } + + public getExtensions(): Promise { + return this._installedExtensionsReady.wait().then(() => { + return this._registry.getAllExtensionDescriptions(); + }); + } + + public getExtension(id: string): Promise { + return this._installedExtensionsReady.wait().then(() => { + return this._registry.getExtensionDescription(id); + }); + } + + public readExtensionPointContributions(extPoint: IExtensionPoint): Promise[]> { + return this._installedExtensionsReady.wait().then(() => { + let availableExtensions = this._registry.getAllExtensionDescriptions(); + + let result: ExtensionPointContribution[] = [], resultLen = 0; + for (let i = 0, len = availableExtensions.length; i < len; i++) { + let desc = availableExtensions[i]; + + if (desc.contributes && hasOwnProperty.call(desc.contributes, extPoint.name)) { + result[resultLen++] = new ExtensionPointContribution(desc, desc.contributes[extPoint.name]); + } + } + + return result; + }); + } + + public getExtensionsStatus(): { [id: string]: IExtensionsStatus; } { + let result: { [id: string]: IExtensionsStatus; } = Object.create(null); + if (this._registry) { + const extensions = this._registry.getAllExtensionDescriptions(); + for (const extension of extensions) { + const extensionKey = ExtensionIdentifier.toKey(extension.identifier); + result[extension.identifier.value] = { + messages: this._extensionsMessages.get(extensionKey) || [], + activationTimes: this._extensionHostProcessActivationTimes.get(extensionKey), + runtimeErrors: this._extensionHostExtensionRuntimeErrors.get(extensionKey) || [], + }; + } + } + return result; + } + + public getInspectPort(): number { + if (this._extensionHostProcessManagers.length > 0) { + return this._extensionHostProcessManagers[0].getInspectPort(); + } + return 0; + } + + // ---- end IExtensionService + // --- impl private createLogger(): Logger { @@ -421,7 +642,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten } } - protected async _scanAndHandleExtensions(): Promise { + private async _scanAndHandleExtensions(): Promise { this._extensionScanner.startScanningExtensions(this.createLogger()); const remoteAuthority = this._environmentService.configuration.remoteAuthority; @@ -429,12 +650,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten let localExtensions = await this._extensionScanner.scannedExtensions; - // enable or disable proposed API per extension - this._checkEnableProposedApi(localExtensions); - - // remove disabled extensions - localExtensions = localExtensions.filter(extension => this._isEnabled(extension)); - if (remoteAuthority) { let resolvedAuthority: ResolvedAuthority; @@ -478,28 +693,37 @@ export class ExtensionService extends AbstractExtensionService implements IExten // fetch the remote environment const remoteEnv = (await this._remoteAgentService.getEnvironment())!; - // enable or disable proposed API per extension - this._checkEnableProposedApi(remoteEnv.extensions); - - // remove disabled extensions - remoteEnv.extensions = remoteEnv.extensions.filter(extension => this._isEnabled(extension)); + // revive URIs + remoteEnv.extensions.forEach((extension) => { + (extension).extensionLocation = URI.revive(extension.extensionLocation); + }); // remove UI extensions from the remote extensions - remoteEnv.extensions = remoteEnv.extensions.filter(extension => !isUIExtension(extension, this._productService, this._configurationService)); + remoteEnv.extensions = remoteEnv.extensions.filter(extension => !isUIExtension(extension, this._configurationService)); // remove non-UI extensions from the local extensions - localExtensions = localExtensions.filter(extension => extension.isBuiltin || isUIExtension(extension, this._productService, this._configurationService)); + localExtensions = localExtensions.filter(extension => extension.isBuiltin || isUIExtension(extension, this._configurationService)); // in case of overlap, the remote wins const isRemoteExtension = new Set(); remoteEnv.extensions.forEach(extension => isRemoteExtension.add(ExtensionIdentifier.toKey(extension.identifier))); localExtensions = localExtensions.filter(extension => !isRemoteExtension.has(ExtensionIdentifier.toKey(extension.identifier))); + // compute enabled extensions + const enabledExtensions = await this._getRuntimeExtensions(([]).concat(remoteEnv.extensions).concat(localExtensions)); + + // remove disabled extensions + const isEnabled = new Set(); + enabledExtensions.forEach(extension => isEnabled.add(ExtensionIdentifier.toKey(extension.identifier))); + remoteEnv.extensions = remoteEnv.extensions.filter(extension => isEnabled.has(ExtensionIdentifier.toKey(extension.identifier))); + localExtensions = localExtensions.filter(extension => isEnabled.has(ExtensionIdentifier.toKey(extension.identifier))); + // save for remote extension's init data this._remoteExtensionsEnvironmentData.set(remoteAuthority, remoteEnv); - this._handleExtensionPoints(([]).concat(remoteEnv.extensions).concat(localExtensions)); + this._handleExtensionPoints(enabledExtensions); extensionHost.start(localExtensions.map(extension => extension.identifier)); + this._releaseBarrier(); } else { await this._startLocalExtensionHost(extensionHost, localExtensions); @@ -507,8 +731,11 @@ export class ExtensionService extends AbstractExtensionService implements IExten } private async _startLocalExtensionHost(extensionHost: ExtensionHostProcessManager, localExtensions: IExtensionDescription[]): Promise { - this._handleExtensionPoints(localExtensions); - extensionHost.start(localExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id))); + const enabledExtensions = await this._getRuntimeExtensions(localExtensions); + + this._handleExtensionPoints(enabledExtensions); + extensionHost.start(enabledExtensions.map(extension => extension.identifier).filter(id => this._registry.containsExtension(id))); + this._releaseBarrier(); } private _handleExtensionPoints(allExtensions: IExtensionDescription[]): void { @@ -517,19 +744,234 @@ export class ExtensionService extends AbstractExtensionService implements IExten this._logOrShowMessage(Severity.Error, nls.localize('looping', "The following extensions contain dependency loops and have been disabled: {0}", result.removedDueToLooping.map(e => `'${e.identifier.value}'`).join(', '))); } - this._doHandleExtensionPoints(this._registry.getAllExtensionDescriptions()); + let availableExtensions = this._registry.getAllExtensionDescriptions(); + let extensionPoints = ExtensionsRegistry.getExtensionPoints(); + + let messageHandler = (msg: IMessage) => this._handleExtensionPointMessage(msg); + + for (let i = 0, len = extensionPoints.length; i < len; i++) { + ExtensionService._handleExtensionPoint(extensionPoints[i], availableExtensions, messageHandler); + } } - public getInspectPort(): number { - if (this._extensionHostProcessManagers.length > 0) { - return this._extensionHostProcessManagers[0].getInspectPort(); + private _releaseBarrier(): void { + perf.mark('extensionHostReady'); + this._installedExtensionsReady.open(); + this._onDidRegisterExtensions.fire(undefined); + this._onDidChangeExtensionsStatus.fire(this._registry.getAllExtensionDescriptions().map(e => e.identifier)); + } + + private isExtensionUnderDevelopment(extension: IExtensionDescription): boolean { + if (this._environmentService.isExtensionDevelopment) { + const extDevLocs = this._environmentService.extensionDevelopmentLocationURI; + if (extDevLocs) { + const extLocation = extension.extensionLocation; + for (let p of extDevLocs) { + if (isEqualOrParent(extLocation, p)) { + return true; + } + } + } } - return 0; + return false; + } + + private async _getRuntimeExtensions(allExtensions: IExtensionDescription[]): Promise { + + const runtimeExtensions: IExtensionDescription[] = []; + const extensionsToDisable: IExtensionDescription[] = []; + const userMigratedSystemExtensions: IExtensionIdentifier[] = [{ id: BetterMergeId }]; + + let enableProposedApiFor: string | string[] = this._environmentService.args['enable-proposed-api'] || []; + + const notFound = (id: string) => nls.localize('notFound', "Extension \`{0}\` cannot use PROPOSED API as it cannot be found", id); + + if (enableProposedApiFor.length) { + let allProposed = (enableProposedApiFor instanceof Array ? enableProposedApiFor : [enableProposedApiFor]); + allProposed.forEach(id => { + if (!allExtensions.some(description => ExtensionIdentifier.equals(description.identifier, id))) { + console.error(notFound(id)); + } + }); + // Make enabled proposed API be lowercase for case insensitive comparison + if (Array.isArray(enableProposedApiFor)) { + enableProposedApiFor = enableProposedApiFor.map(id => id.toLowerCase()); + } else { + enableProposedApiFor = enableProposedApiFor.toLowerCase(); + } + } + + const enableProposedApiForAll = !this._environmentService.isBuilt || + (!!this._environmentService.extensionDevelopmentLocationURI && product.nameLong !== 'Visual Studio Code') || + (enableProposedApiFor.length === 0 && 'enable-proposed-api' in this._environmentService.args); + + + for (const extension of allExtensions) { + + // Do not disable extensions under development + if (!this.isExtensionUnderDevelopment(extension)) { + if (!this._extensionEnablementService.isEnabled(toExtension(extension))) { + continue; + } + } + + if (!extension.isBuiltin) { + // Check if the extension is changed to system extension + const userMigratedSystemExtension = userMigratedSystemExtensions.filter(userMigratedSystemExtension => areSameExtensions(userMigratedSystemExtension, { id: extension.identifier.value }))[0]; + if (userMigratedSystemExtension) { + extensionsToDisable.push(extension); + continue; + } + } + runtimeExtensions.push(this._updateEnableProposedApi(extension, enableProposedApiForAll, enableProposedApiFor)); + } + + this._telemetryService.publicLog('extensionsScanned', { + totalCount: runtimeExtensions.length, + disabledCount: allExtensions.length - runtimeExtensions.length + }); + + if (extensionsToDisable.length) { + return this._extensionEnablementService.setEnablement(extensionsToDisable.map(e => toExtension(e)), EnablementState.Disabled) + .then(() => runtimeExtensions); + } else { + return runtimeExtensions; + } + } + + private _updateEnableProposedApi(extension: IExtensionDescription, enableProposedApiForAll: boolean, enableProposedApiFor: string | string[]): IExtensionDescription { + if (allowProposedApiFromProduct(extension.identifier)) { + // fast lane -> proposed api is available to all extensions + // that are listed in product.json-files + extension.enableProposedApi = true; + + } else if (extension.enableProposedApi && !extension.isBuiltin) { + if ( + !enableProposedApiForAll && + enableProposedApiFor.indexOf(extension.identifier.value.toLowerCase()) < 0 + ) { + extension.enableProposedApi = false; + console.error(`Extension '${extension.identifier.value} cannot use PROPOSED API (must started out of dev or enabled via --enable-proposed-api)`); + + } else { + // proposed api is available when developing or when an extension was explicitly + // spelled out via a command line argument + console.warn(`Extension '${extension.identifier.value}' uses PROPOSED API which is subject to change and removal without notice.`); + } + } + return extension; + } + + private _handleExtensionPointMessage(msg: IMessage) { + const extensionKey = ExtensionIdentifier.toKey(msg.extensionId); + + if (!this._extensionsMessages.has(extensionKey)) { + this._extensionsMessages.set(extensionKey, []); + } + this._extensionsMessages.get(extensionKey)!.push(msg); + + const extension = this._registry.getExtensionDescription(msg.extensionId); + const strMsg = `[${msg.extensionId.value}]: ${msg.message}`; + if (extension && extension.isUnderDevelopment) { + // This message is about the extension currently being developed + this._showMessageToUser(msg.type, strMsg); + } else { + this._logMessageInConsole(msg.type, strMsg); + } + + if (!this._isDev && msg.extensionId) { + const { type, extensionId, extensionPointId, message } = msg; + /* __GDPR__ + "extensionsMessage" : { + "type" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "extensionId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "extensionPointId": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" }, + "message": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } + } + */ + this._telemetryService.publicLog('extensionsMessage', { + type, extensionId: extensionId.value, extensionPointId, message + }); + } + } + + private static _handleExtensionPoint(extensionPoint: ExtensionPoint, availableExtensions: IExtensionDescription[], messageHandler: (msg: IMessage) => void): void { + let users: IExtensionPointUser[] = [], usersLen = 0; + for (let i = 0, len = availableExtensions.length; i < len; i++) { + let desc = availableExtensions[i]; + + if (desc.contributes && hasOwnProperty.call(desc.contributes, extensionPoint.name)) { + users[usersLen++] = { + description: desc, + value: desc.contributes[extensionPoint.name], + collector: new ExtensionMessageCollector(messageHandler, desc, extensionPoint.name) + }; + } + } + + extensionPoint.acceptUsers(users); + } + + private _showMessageToUser(severity: Severity, msg: string): void { + if (severity === Severity.Error || severity === Severity.Warning) { + this._notificationService.notify({ severity, message: msg }); + } else { + this._logMessageInConsole(severity, msg); + } + } + + private _logMessageInConsole(severity: Severity, msg: string): void { + if (severity === Severity.Error) { + console.error(msg); + } else if (severity === Severity.Warning) { + console.warn(msg); + } else { + console.log(msg); + } + } + + // -- called by extension host + + public _logOrShowMessage(severity: Severity, msg: string): void { + if (this._isDev) { + this._showMessageToUser(severity, msg); + } else { + this._logMessageInConsole(severity, msg); + } + } + + public async _activateById(extensionId: ExtensionIdentifier, activationEvent: string): Promise { + const results = await Promise.all( + this._extensionHostProcessManagers.map(manager => manager.activate(extensionId, activationEvent)) + ); + const activated = results.some(e => e); + if (!activated) { + throw new Error(`Unknown extension ${extensionId.value}`); + } + } + + public _onWillActivateExtension(extensionId: ExtensionIdentifier): void { + this._extensionHostActiveExtensions.set(ExtensionIdentifier.toKey(extensionId), extensionId); + } + + public _onDidActivateExtension(extensionId: ExtensionIdentifier, startup: boolean, codeLoadingTime: number, activateCallTime: number, activateResolvedTime: number, activationEvent: string): void { + this._extensionHostProcessActivationTimes.set(ExtensionIdentifier.toKey(extensionId), new ActivationTimes(startup, codeLoadingTime, activateCallTime, activateResolvedTime, activationEvent)); + this._onDidChangeExtensionsStatus.fire([extensionId]); + } + + public _onExtensionRuntimeError(extensionId: ExtensionIdentifier, err: Error): void { + const extensionKey = ExtensionIdentifier.toKey(extensionId); + if (!this._extensionHostExtensionRuntimeErrors.has(extensionKey)) { + this._extensionHostExtensionRuntimeErrors.set(extensionKey, []); + } + this._extensionHostExtensionRuntimeErrors.get(extensionKey)!.push(err); + this._onDidChangeExtensionsStatus.fire([extensionId]); } public _onExtensionHostExit(code: number): void { // Expected development extension termination: When the extension host goes down we also shutdown the window - if (!this._isExtensionDevTestFromCli) { + const devOpts = parseExtensionDevOptions(this._environmentService); + if (!devOpts.isExtensionDevTestFromCli) { this._windowService.closeWindow(); } diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionHostClient.ts similarity index 86% rename from src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts rename to src/vs/workbench/services/extensions/electron-browser/remoteExtensionHostClient.ts index 26e1a16b61..4ba888e057 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/electron-browser/remoteExtensionHostClient.ts @@ -3,13 +3,17 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import { ipcRenderer as ipc } from 'electron'; import { Emitter, Event } from 'vs/base/common/event'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { ILabelService } from 'vs/platform/label/common/label'; import { ILogService } from 'vs/platform/log/common/log'; -import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, IWebSocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; +import product from 'vs/platform/product/node/product'; +import pkg from 'vs/platform/product/node/package'; +import { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; +import { IWindowService } from 'vs/platform/windows/common/windows'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; @@ -24,8 +28,8 @@ import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { VSBuffer } from 'vs/base/common/buffer'; +import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; import { IExtensionHostDebugService } from 'vs/workbench/services/extensions/common/extensionHostDebug'; -import { IProductService } from 'vs/platform/product/common/product'; export interface IInitDataProvider { readonly remoteAuthority: string; @@ -34,28 +38,28 @@ export interface IInitDataProvider { export class RemoteExtensionHostClient extends Disposable implements IExtensionHostStarter { - private _onExit: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>()); - public readonly onExit: Event<[number, string | null]> = this._onExit.event; + private _onCrashed: Emitter<[number, string | null]> = this._register(new Emitter<[number, string | null]>()); + public readonly onCrashed: Event<[number, string | null]> = this._onCrashed.event; private _protocol: PersistentProtocol | null; private readonly _isExtensionDevHost: boolean; + private readonly _isExtensionDevTestFromCli: boolean; private _terminating: boolean; constructor( private readonly _allExtensions: Promise, private readonly _initDataProvider: IInitDataProvider, - private readonly _webSocketFactory: IWebSocketFactory, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, + @IWindowService private readonly _windowService: IWindowService, @ILifecycleService private readonly _lifecycleService: ILifecycleService, @ILogService private readonly _logService: ILogService, @ILabelService private readonly _labelService: ILabelService, @IRemoteAuthorityResolverService private readonly remoteAuthorityResolverService: IRemoteAuthorityResolverService, - @IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService, - @IProductService private readonly _productService: IProductService + @IExtensionHostDebugService private readonly _extensionHostDebugService: IExtensionHostDebugService ) { super(); this._protocol = null; @@ -65,13 +69,14 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH const devOpts = parseExtensionDevOptions(this._environmentService); this._isExtensionDevHost = devOpts.isExtensionDevHost; + this._isExtensionDevTestFromCli = devOpts.isExtensionDevTestFromCli; } public start(): Promise { const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, - commit: this._productService.commit, - webSocketFactory: this._webSocketFactory, + commit: product.commit, + webSocketFactory: nodeWebSocketFactory, addressProvider: { getAddress: async () => { const { host, port } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority); @@ -163,7 +168,20 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH return; } - this._onExit.fire([0, null]); + // Unexpected termination + if (!this._isExtensionDevHost) { + this._onCrashed.fire([0, null]); + } + + // Expected development extension termination: When the extension host goes down we also shutdown the window + else if (!this._isExtensionDevTestFromCli) { + this._windowService.closeWindow(); + } + + // When CLI testing make sure to exit with proper exit code + else { + ipc.send('vscode:exit', 0); + } } private _createExtHostInitData(isExtensionDevelopmentDebug: boolean): Promise { @@ -173,15 +191,15 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH const hostExtensions = allExtensions.filter(extension => extension.main && extension.api === 'none').map(extension => extension.identifier); const workspace = this._contextService.getWorkspace(); const r: IInitData = { - commit: this._productService.commit, - version: this._productService.version, + commit: product.commit, + version: pkg.version, parentPid: remoteExtensionHostData.pid, environment: { isExtensionDevelopmentDebug, appRoot: remoteExtensionHostData.appRoot, appSettingsHome: remoteExtensionHostData.appSettingsHome, - appName: this._productService.nameLong, - appUriScheme: this._productService.urlProtocol, + appName: product.nameLong, + appUriScheme: product.urlProtocol, appLanguage: platform.language, extensionDevelopmentLocationURI: this._environmentService.extensionDevelopmentLocationURI, extensionTestsLocationURI: this._environmentService.extensionTestsLocationURI, diff --git a/src/vs/workbench/services/extensions/node/extensionHostMain.ts b/src/vs/workbench/services/extensions/node/extensionHostMain.ts index d2d1cf46aa..60e47348ba 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostMain.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostMain.ts @@ -19,6 +19,7 @@ import { RPCProtocol } from 'vs/workbench/services/extensions/common/rpcProtocol import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { withNullAsUndefined } from 'vs/base/common/types'; import { ILogService } from 'vs/platform/log/common/log'; +import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; // we don't (yet) throw when extensions parse // uris that have no scheme @@ -52,7 +53,9 @@ export class ExtensionHostMain { hostUtils: IHostUtils, consolePatchFn: IConsolePatchFn, logServiceFn: ILogServiceFn, - uriTransformer: IURITransformer | null + uriTransformer: IURITransformer | null, + schemeTransformer: ISchemeTransformer | null, + outputChannelName: string, ) { this._isTerminating = false; this._hostUtils = hostUtils; @@ -83,7 +86,8 @@ export class ExtensionHostMain { extHostConfiguraiton, initData.environment, this._extHostLogService, - uriTransformer + schemeTransformer, + outputChannelName ); // error forwarding and stack trace scanning diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts index b43ea6602c..f8f0ec2bc9 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcess.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcess.ts @@ -3,6 +3,11 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; import { startExtensionHostProcess } from 'vs/workbench/services/extensions/node/extensionHostProcessSetup'; -startExtensionHostProcess().catch((err) => console.log(err)); +startExtensionHostProcess( + _ => null, + _ => null, + _ => nls.localize('extension host Log', "Extension Host") +).catch((err) => console.log(err)); diff --git a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts index 9994b3103f..2e303b8f5f 100644 --- a/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts +++ b/src/vs/workbench/services/extensions/node/extensionHostProcessSetup.ts @@ -5,33 +5,23 @@ import * as nativeWatchdog from 'native-watchdog'; import * as net from 'net'; -import * as minimist from 'minimist'; import { onUnexpectedError } from 'vs/base/common/errors'; -import { Event, Emitter } from 'vs/base/common/event'; +import { Event } from 'vs/base/common/event'; import { IMessagePassingProtocol } from 'vs/base/parts/ipc/common/ipc'; -import { PersistentProtocol, ProtocolConstants, createBufferedEvent } from 'vs/base/parts/ipc/common/ipc.net'; -import { NodeSocket, WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { PersistentProtocol, ProtocolConstants } from 'vs/base/parts/ipc/common/ipc.net'; +import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import product from 'vs/platform/product/node/product'; import { IInitData, MainThreadConsoleShape } from 'vs/workbench/api/common/extHost.protocol'; import { MessageType, createMessageOfType, isMessageOfType, IExtHostSocketMessage, IExtHostReadyMessage } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostMain, IExitFn, ILogServiceFn } from 'vs/workbench/services/extensions/node/extensionHostMain'; import { VSBuffer } from 'vs/base/common/buffer'; +import { createBufferSpdLogService } from 'vs/platform/log/node/spdlogService'; import { ExtensionHostLogFileName } from 'vs/workbench/services/extensions/common/extensions'; -import { IURITransformer, URITransformer, IRawURITransformer } from 'vs/base/common/uriIpc'; +import { ISchemeTransformer } from 'vs/workbench/api/common/extHostLanguageFeatures'; +import { IURITransformer } from 'vs/base/common/uriIpc'; import { exists } from 'vs/base/node/pfs'; import { realpath } from 'vs/base/node/extpath'; import { IHostUtils } from 'vs/workbench/api/node/extHostExtensionService'; -import { SpdLogService } from 'vs/platform/log/node/spdlogService'; - -interface ParsedExtHostArgs { - uriTransformerPath?: string; -} - -const args = minimist(process.argv.slice(2), { - string: [ - 'uriTransformerPath' - ] -}) as ParsedExtHostArgs; // With Electron 2.x and node.js 8.x the "natives" module // can cause a native crash (see https://github.com/nodejs/node/issues/19891 and @@ -82,7 +72,7 @@ function patchPatchedConsole(mainThreadConsole: MainThreadConsoleShape): void { }; } -const createLogService: ILogServiceFn = initData => new SpdLogService(ExtensionHostLogFileName, initData.logsLocation.fsPath, initData.logLevel); +const createLogService: ILogServiceFn = initData => createBufferSpdLogService(ExtensionHostLogFileName, initData.logLevel, initData.logsLocation.fsPath); interface IRendererConnection { protocol: IMessagePassingProtocol; @@ -111,41 +101,27 @@ function _createExtHostProtocol(): Promise { process.on('message', (msg: IExtHostSocketMessage, handle: net.Socket) => { if (msg && msg.type === 'VSCODE_EXTHOST_IPC_SOCKET') { const initialDataChunk = VSBuffer.wrap(Buffer.from(msg.initialDataChunk, 'base64')); - let socket: NodeSocket | WebSocketNodeSocket; - if (msg.skipWebSocketFrames) { - socket = new NodeSocket(handle); - } else { - socket = new WebSocketNodeSocket(new NodeSocket(handle)); - } if (protocol) { // reconnection case if (disconnectWaitTimer) { clearTimeout(disconnectWaitTimer); disconnectWaitTimer = null; } - protocol.beginAcceptReconnection(socket, initialDataChunk); + protocol.beginAcceptReconnection(new NodeSocket(handle), initialDataChunk); protocol.endAcceptReconnection(); } else { clearTimeout(timer); - protocol = new PersistentProtocol(socket, initialDataChunk); + protocol = new PersistentProtocol(new NodeSocket(handle), initialDataChunk); protocol.onClose(() => onTerminate()); resolve(protocol); - if (msg.skipWebSocketFrames) { - // Wait for rich client to reconnect - protocol.onSocketClose(() => { - // The socket has closed, let's give the renderer a certain amount of time to reconnect - disconnectWaitTimer = setTimeout(() => { - disconnectWaitTimer = null; - onTerminate(); - }, ProtocolConstants.ReconnectionGraceTime); - }); - } else { - // Do not wait for web companion to reconnect - protocol.onSocketClose(() => { + protocol.onSocketClose(() => { + // The socket has closed, let's give the renderer a certain amount of time to reconnect + disconnectWaitTimer = setTimeout(() => { + disconnectWaitTimer = null; onTerminate(); - }); - } + }, ProtocolConstants.ReconnectionGraceTime); + }); } } }); @@ -179,22 +155,16 @@ async function createExtHostProtocol(): Promise { return new class implements IMessagePassingProtocol { - private readonly _onMessage = new Emitter(); - readonly onMessage: Event = createBufferedEvent(this._onMessage.event); + private _terminating = false; - private _terminating: boolean; - - constructor() { - this._terminating = false; - protocol.onMessage((msg) => { - if (isMessageOfType(msg, MessageType.Terminate)) { - this._terminating = true; - onTerminate(); - } else { - this._onMessage.fire(msg); - } - }); - } + readonly onMessage: Event = Event.filter(protocol.onMessage, msg => { + if (!isMessageOfType(msg, MessageType.Terminate)) { + return true; + } + this._terminating = true; + onTerminate(); + return false; + }); send(msg: any): void { if (!this._terminating) { @@ -302,7 +272,11 @@ function connectToRenderer(protocol: IMessagePassingProtocol): Promise { +export async function startExtensionHostProcess( + uriTransformerFn: (initData: IInitData) => IURITransformer | null, + schemeTransformerFn: (initData: IInitData) => ISchemeTransformer | null, + outputChannelNameFn: (initData: IInitData) => string, +): Promise { const protocol = await createExtHostProtocol(); const renderer = await connectToRenderer(protocol); @@ -317,17 +291,6 @@ export async function startExtensionHostProcess(): Promise { realpath(path: string) { return realpath(path); } }; - // Attempt to load uri transformer - let uriTransformer: IURITransformer | null = null; - if (initData.remoteAuthority && args.uriTransformerPath) { - try { - const rawURITransformerFactory = require.__$__nodeRequire(args.uriTransformerPath); - const rawURITransformer = rawURITransformerFactory(initData.remoteAuthority); - uriTransformer = new URITransformer(rawURITransformer); - } catch (e) { - console.error(e); - } - } const extensionHostMain = new ExtensionHostMain( renderer.protocol, @@ -335,7 +298,9 @@ export async function startExtensionHostProcess(): Promise { hostUtils, patchPatchedConsole, createLogService, - uriTransformer + uriTransformerFn(initData), + schemeTransformerFn(initData), + outputChannelNameFn(initData) ); // rewrite onTerminate-function to be a proper shutdown diff --git a/src/vs/workbench/services/extensions/node/extensionPoints.ts b/src/vs/workbench/services/extensions/node/extensionPoints.ts index 169a3370fe..90f69da182 100644 --- a/src/vs/workbench/services/extensions/node/extensionPoints.ts +++ b/src/vs/workbench/services/extensions/node/extensionPoints.ts @@ -12,13 +12,40 @@ import { getParseErrorMessage } from 'vs/base/common/jsonErrorMessages'; import * as types from 'vs/base/common/types'; import { URI } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; -import { getGalleryExtensionId, groupByExtension, ExtensionIdentifierWithVersion } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; +import { getGalleryExtensionId, groupByExtension } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isValidExtensionVersion } from 'vs/platform/extensions/node/extensionValidator'; -import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; -import { Translations, ILog } from 'vs/workbench/services/extensions/common/extensionPoints'; +import { ExtensionIdentifier, ExtensionIdentifierWithVersion, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; const MANIFEST_FILE = 'package.json'; +export interface Translations { + [id: string]: string; +} + +namespace Translations { + export function equals(a: Translations, b: Translations): boolean { + if (a === b) { + return true; + } + let aKeys = Object.keys(a); + let bKeys: Set = new Set(); + for (let key of Object.keys(b)) { + bKeys.add(key); + } + if (aKeys.length !== bKeys.size) { + return false; + } + + for (let key of aKeys) { + if (a[key] !== b[key]) { + return false; + } + bKeys.delete(key); + } + return bKeys.size === 0; + } +} + export interface NlsConfiguration { readonly devMode: boolean; readonly locale: string | undefined; @@ -26,6 +53,12 @@ export interface NlsConfiguration { readonly translations: Translations; } +export interface ILog { + error(source: string, message: string): void; + warn(source: string, message: string): void; + info(source: string, message: string): void; +} + abstract class ExtensionManifestHandler { protected readonly _ourVersion: string; diff --git a/src/vs/workbench/services/extensions/common/extensionsUtil.ts b/src/vs/workbench/services/extensions/node/extensionsUtil.ts similarity index 86% rename from src/vs/workbench/services/extensions/common/extensionsUtil.ts rename to src/vs/workbench/services/extensions/node/extensionsUtil.ts index 9b4699fc75..8fe148d902 100644 --- a/src/vs/workbench/services/extensions/common/extensionsUtil.ts +++ b/src/vs/workbench/services/extensions/node/extensionsUtil.ts @@ -8,9 +8,9 @@ import { IExtensionManifest } from 'vs/platform/extensions/common/extensions'; import { ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { getGalleryExtensionId, areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { isNonEmptyArray } from 'vs/base/common/arrays'; -import { IProductService } from 'vs/platform/product/common/product'; +import product from 'vs/platform/product/node/product'; -export function isUIExtension(manifest: IExtensionManifest, productService: IProductService, configurationService: IConfigurationService): boolean { +export function isUIExtension(manifest: IExtensionManifest, configurationService: IConfigurationService): boolean { const uiContributions = ExtensionsRegistry.getExtensionPoints().filter(e => e.defaultExtensionKind !== 'workspace').map(e => e.name); const extensionId = getGalleryExtensionId(manifest.publisher, manifest.name); const extensionKind = getExtensionKind(manifest, configurationService); @@ -19,7 +19,7 @@ export function isUIExtension(manifest: IExtensionManifest, productService: IPro case 'workspace': return false; default: { // Tagged as UI extension in product - if (isNonEmptyArray(productService.uiExtensions) && productService.uiExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) { + if (isNonEmptyArray(product.uiExtensions) && product.uiExtensions.some(id => areSameExtensions({ id }, { id: extensionId }))) { return true; } // Not an UI extension if it has main diff --git a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts b/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts index 0fa330490a..171b524764 100644 --- a/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts +++ b/src/vs/workbench/services/extensions/node/multiExtensionManagement.ts @@ -16,11 +16,10 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { getManifest } from 'vs/platform/extensionManagement/node/extensionManagementUtil'; import { areSameExtensions } from 'vs/platform/extensionManagement/common/extensionManagementUtil'; import { localize } from 'vs/nls'; -import { isUIExtension } from 'vs/workbench/services/extensions/common/extensionsUtil'; +import { isUIExtension } from 'vs/workbench/services/extensions/node/extensionsUtil'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { isNonEmptyArray } from 'vs/base/common/arrays'; import { values } from 'vs/base/common/map'; -import { IProductService } from 'vs/platform/product/common/product'; export class MultiExtensionManagementService extends Disposable implements IExtensionManagementService { @@ -36,8 +35,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte constructor( @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, - @IConfigurationService private readonly configurationService: IConfigurationService, - @IProductService private readonly productService: IProductService, + @IConfigurationService private readonly configurationService: IConfigurationService ) { super(); this.servers = this.extensionManagementServerService.remoteExtensionManagementServer ? [this.extensionManagementServerService.localExtensionManagementServer, this.extensionManagementServerService.remoteExtensionManagementServer] : [this.extensionManagementServerService.localExtensionManagementServer]; @@ -87,7 +85,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte private async uninstallInServer(extension: ILocalExtension, server: IExtensionManagementServer, force?: boolean): Promise { if (server === this.extensionManagementServerService.localExtensionManagementServer) { const installedExtensions = await this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.getInstalled(ExtensionType.User); - const dependentNonUIExtensions = installedExtensions.filter(i => !isUIExtension(i.manifest, this.productService, this.configurationService) + const dependentNonUIExtensions = installedExtensions.filter(i => !isUIExtension(i.manifest, this.configurationService) && i.manifest.extensionDependencies && i.manifest.extensionDependencies.some(id => areSameExtensions({ id }, extension.identifier))); if (dependentNonUIExtensions.length) { return Promise.reject(new Error(this.getDependentsErrorMessage(extension, dependentNonUIExtensions))); @@ -142,7 +140,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte const [extensionIdentifier] = await Promise.all(this.servers.map(server => server.extensionManagementService.install(vsix))); return extensionIdentifier; } - if (isUIExtension(manifest, this.productService, this.configurationService)) { + if (isUIExtension(manifest, this.configurationService)) { // Install only on local server return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.install(vsix); } @@ -163,7 +161,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte // Install on both servers return Promise.all(this.servers.map(server => server.extensionManagementService.installFromGallery(gallery))).then(() => undefined); } - if (isUIExtension(manifest, this.productService, this.configurationService)) { + if (isUIExtension(manifest, this.configurationService)) { // Install only on local server return this.extensionManagementServerService.localExtensionManagementServer.extensionManagementService.installFromGallery(gallery); } @@ -212,7 +210,7 @@ export class MultiExtensionManagementService extends Disposable implements IExte for (let idx = 0; idx < extensions.length; idx++) { const extension = extensions[idx]; const manifest = manifests[idx]; - if (manifest && isUIExtension(manifest, this.productService, this.configurationService)) { + if (manifest && isUIExtension(manifest, this.configurationService)) { result.set(extension.identifier.id.toLowerCase(), extension); uiExtensionsManifests.push(manifest); } diff --git a/src/vs/workbench/services/extensions/node/proxyResolver.ts b/src/vs/workbench/services/extensions/node/proxyResolver.ts index c921028712..2e3727a962 100644 --- a/src/vs/workbench/services/extensions/node/proxyResolver.ts +++ b/src/vs/workbench/services/extensions/node/proxyResolver.ts @@ -457,8 +457,8 @@ async function readCaCertificates() { return undefined; } -async function readWindowsCaCertificates() { - const winCA = await import('vscode-windows-ca-certs'); +function readWindowsCaCertificates() { + const winCA = require.__$__nodeRequire('vscode-windows-ca-certs'); let ders: any[] = []; const store = winCA(); @@ -481,14 +481,7 @@ async function readWindowsCaCertificates() { } async function readMacCaCertificates() { - const stdout = await new Promise((resolve, reject) => { - const child = cp.spawn('/usr/bin/security', ['find-certificate', '-a', '-p']); - const stdout: string[] = []; - child.stdout.setEncoding('utf8'); - child.stdout.on('data', str => stdout.push(str)); - child.on('error', reject); - child.on('exit', code => code ? reject(code) : resolve(stdout.join(''))); - }); + const stdout = (await promisify(cp.execFile)('/usr/bin/security', ['find-certificate', '-a', '-p'], { encoding: 'utf8', maxBuffer: 1024 * 1024 })).stdout; const seen = {}; const certs = stdout.split(/(?=-----BEGIN CERTIFICATE-----)/g) .filter(pem => !!pem.length && !seen[pem] && (seen[pem] = true)); diff --git a/src/vs/workbench/services/files/common/fileService.ts b/src/vs/workbench/services/files/common/fileService.ts index c7416844d0..0ee4793ddc 100644 --- a/src/vs/workbench/services/files/common/fileService.ts +++ b/src/vs/workbench/services/files/common/fileService.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { Disposable, IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle'; +import { Disposable, IDisposable, toDisposable, combinedDisposable, dispose } from 'vs/base/common/lifecycle'; import { IFileService, IResolveFileOptions, FileChangesEvent, FileOperationEvent, IFileSystemProviderRegistrationEvent, IFileSystemProvider, IFileStat, IResolveFileResult, ICreateFileOptions, IFileSystemProviderActivationEvent, FileOperationError, FileOperationResult, FileOperation, FileSystemProviderCapabilities, FileType, toFileSystemProviderErrorCode, FileSystemProviderErrorCode, IStat, IFileStatWithMetadata, IResolveMetadataFileOptions, etag, hasReadWriteCapability, hasFileFolderCopyCapability, hasOpenReadWriteCloseCapability, toFileOperationResult, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IResolveFileResultWithMetadata, IWatchOptions, IWriteFileOptions, IReadFileOptions, IFileStreamContent, IFileContent, ETAG_DISABLED } from 'vs/platform/files/common/files'; import { URI } from 'vs/base/common/uri'; import { Event, Emitter } from 'vs/base/common/event'; @@ -55,12 +55,14 @@ export class FileService extends Disposable implements IFileService { providerDisposables.push(provider.onDidErrorOccur(error => this._onError.fire(error))); } - return toDisposable(() => { - this._onDidChangeFileSystemProviderRegistrations.fire({ added: false, scheme, provider }); - this.provider.delete(scheme); + return combinedDisposable([ + toDisposable(() => { + this._onDidChangeFileSystemProviderRegistrations.fire({ added: false, scheme, provider }); + this.provider.delete(scheme); - dispose(providerDisposables); - }); + dispose(providerDisposables); + }) + ]); } async activateProvider(scheme: string): Promise { @@ -78,7 +80,7 @@ export class FileService extends Disposable implements IFileService { }); if (this.provider.has(scheme)) { - return; // provider is already here so we can return directly + return Promise.resolve(); // provider is already here so we can return directly } // If the provider is not yet there, make sure to join on the listeners assuming @@ -235,7 +237,7 @@ export class FileService extends Disposable implements IFileService { return fileStat; } - return fileStat; + return Promise.resolve(fileStat); } async resolveAll(toResolve: { resource: URI, options?: IResolveFileOptions }[]): Promise; diff --git a/src/vs/workbench/services/files/test/node/diskFileService.test.ts b/src/vs/workbench/services/files/test/node/diskFileService.test.ts index 9c87b78977..328718350c 100644 --- a/src/vs/workbench/services/files/test/node/diskFileService.test.ts +++ b/src/vs/workbench/services/files/test/node/diskFileService.test.ts @@ -18,7 +18,7 @@ import { existsSync, statSync, readdirSync, readFileSync, writeFileSync, renameS import { FileOperation, FileOperationEvent, IFileStat, FileOperationResult, FileSystemProviderCapabilities, FileChangeType, IFileChange, FileChangesEvent, FileOperationError, etag, IStat } from 'vs/platform/files/common/files'; import { NullLogService } from 'vs/platform/log/common/log'; import { isLinux, isWindows } from 'vs/base/common/platform'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { isEqual } from 'vs/base/common/resources'; import { VSBuffer, VSBufferReadable } from 'vs/base/common/buffer'; @@ -125,21 +125,21 @@ suite('Disk File Service', () => { let testProvider: TestDiskFileSystemProvider; let testDir: string; - const disposables = new DisposableStore(); + let disposables: IDisposable[] = []; setup(async () => { const logService = new NullLogService(); service = new FileService(logService); - disposables.add(service); + disposables.push(service); fileProvider = new TestDiskFileSystemProvider(logService); - disposables.add(service.registerProvider(Schemas.file, fileProvider)); - disposables.add(fileProvider); + disposables.push(service.registerProvider(Schemas.file, fileProvider)); + disposables.push(fileProvider); testProvider = new TestDiskFileSystemProvider(logService); - disposables.add(service.registerProvider(testSchema, testProvider)); - disposables.add(testProvider); + disposables.push(service.registerProvider(testSchema, testProvider)); + disposables.push(testProvider); const id = generateUuid(); testDir = join(parentDir, id); @@ -149,14 +149,14 @@ suite('Disk File Service', () => { }); teardown(async () => { - disposables.clear(); + disposables = dispose(disposables); await rimraf(parentDir, RimRafMode.MOVE); }); test('createFolder', async () => { let event: FileOperationEvent | undefined; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const parent = await service.resolve(URI.file(testDir)); @@ -176,7 +176,7 @@ suite('Disk File Service', () => { test('createFolder: creating multiple folders at once', async function () { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const multiFolderPaths = ['a', 'couple', 'of', 'folders']; const parent = await service.resolve(URI.file(testDir)); @@ -411,7 +411,7 @@ suite('Disk File Service', () => { test('deleteFile', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const resource = URI.file(join(testDir, 'deep', 'conway.js')); const source = await service.resolve(resource); @@ -426,7 +426,7 @@ suite('Disk File Service', () => { test('deleteFolder (recursive)', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const resource = URI.file(join(testDir, 'deep')); const source = await service.resolve(resource); @@ -446,14 +446,15 @@ suite('Disk File Service', () => { await service.del(source.resource); return Promise.reject(new Error('Unexpected')); - } catch (error) { + } + catch (error) { return Promise.resolve(true); } }); test('move', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = URI.file(join(testDir, 'index.html')); const sourceContents = readFileSync(source.fsPath); @@ -533,7 +534,7 @@ suite('Disk File Service', () => { async function testMoveAcrossProviders(sourceFile = 'index.html'): Promise { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = URI.file(join(testDir, sourceFile)); const sourceContents = readFileSync(source.fsPath); @@ -557,7 +558,7 @@ suite('Disk File Service', () => { test('move - multi folder', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const multiFolderPaths = ['a', 'couple', 'of', 'folders']; const renameToPath = join(...multiFolderPaths, 'other.html'); @@ -576,7 +577,7 @@ suite('Disk File Service', () => { test('move - directory', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = URI.file(join(testDir, 'deep')); @@ -620,7 +621,7 @@ suite('Disk File Service', () => { async function testMoveFolderAcrossProviders(): Promise { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = URI.file(join(testDir, 'deep')); const sourceChildren = readdirSync(source.fsPath); @@ -645,7 +646,7 @@ suite('Disk File Service', () => { test('move - MIX CASE', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = URI.file(join(testDir, 'index.html')); await service.resolve(source); @@ -662,7 +663,7 @@ suite('Disk File Service', () => { test('move - source parent of target', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); await service.resolve(URI.file(join(testDir, 'index.html'))); try { @@ -675,7 +676,7 @@ suite('Disk File Service', () => { test('move - FILE_MOVE_CONFLICT', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = await service.resolve(URI.file(join(testDir, 'index.html'))); try { @@ -690,7 +691,7 @@ suite('Disk File Service', () => { let createEvent: FileOperationEvent; let moveEvent: FileOperationEvent; let deleteEvent: FileOperationEvent; - disposables.add(service.onAfterOperation(e => { + disposables.push(service.onAfterOperation(e => { if (e.operation === FileOperation.CREATE) { createEvent = e; } else if (e.operation === FileOperation.DELETE) { @@ -754,7 +755,7 @@ suite('Disk File Service', () => { async function doTestCopy(sourceName: string = 'index.html') { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const source = await service.resolve(URI.file(join(testDir, sourceName))); const target = URI.file(join(testDir, 'other.html')); @@ -779,7 +780,7 @@ suite('Disk File Service', () => { let createEvent: FileOperationEvent; let copyEvent: FileOperationEvent; let deleteEvent: FileOperationEvent; - disposables.add(service.onAfterOperation(e => { + disposables.push(service.onAfterOperation(e => { if (e.operation === FileOperation.CREATE) { createEvent = e; } else if (e.operation === FileOperation.DELETE) { @@ -1168,7 +1169,7 @@ suite('Disk File Service', () => { test('createFile', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const contents = 'Hello World'; const resource = URI.file(join(testDir, 'test.txt')); @@ -1199,7 +1200,7 @@ suite('Disk File Service', () => { test('createFile (allows to overwrite existing)', async () => { let event: FileOperationEvent; - disposables.add(service.onAfterOperation(e => event = e)); + disposables.push(service.onAfterOperation(e => event = e)); const contents = 'Hello World'; const resource = URI.file(join(testDir, 'test.txt')); diff --git a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts index e49912a7aa..74dda793dd 100644 --- a/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/electron-browser/keybindingService.ts @@ -28,6 +28,7 @@ import { IKeybindingItem, IKeybindingRule2, KeybindingWeight, KeybindingsRegistr import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { Registry } from 'vs/platform/registry/common/platform'; +import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { keybindingsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils'; import { ExtensionMessageCollector, ExtensionsRegistry } from 'vs/workbench/services/extensions/common/extensionsRegistry'; @@ -40,7 +41,6 @@ import { IWindowService } from 'vs/platform/windows/common/windows'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { commandsExtensionPoint } from 'vs/workbench/api/common/menusExtensionPoint'; export class KeyboardMapperFactory { public static readonly INSTANCE = new KeyboardMapperFactory(); @@ -215,7 +215,7 @@ let keybindingType: IJSONSchema = { description: nls.localize('vscode.extension.contributes.keybindings.args', "Arguments to pass to the command to execute.") }, key: { - description: nls.localize('vscode.extension.contributes.keybindings.key', 'Key or key sequence (separate keys with plus-sign and sequences with space, e.g. Ctrl+O and Ctrl+L L for a chord).'), + description: nls.localize('vscode.extension.contributes.keybindings.key', 'Key or key sequence (separate keys with plus-sign and sequences with space, e.g Ctrl+O and Ctrl+L L for a chord).'), type: 'string' }, mac: { @@ -239,7 +239,6 @@ let keybindingType: IJSONSchema = { const keybindingsExtPoint = ExtensionsRegistry.registerExtensionPoint({ extensionPoint: 'keybindings', - deps: [commandsExtensionPoint], jsonSchema: { description: nls.localize('vscode.extension.contributes.keybindings', "Contributes keybindings."), oneOf: [ @@ -276,11 +275,12 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { @ITelemetryService telemetryService: ITelemetryService, @INotificationService notificationService: INotificationService, @IEnvironmentService environmentService: IEnvironmentService, + @IStatusbarService statusBarService: IStatusbarService, @IConfigurationService configurationService: IConfigurationService, @IWindowService private readonly windowService: IWindowService, @IExtensionService extensionService: IExtensionService ) { - super(contextKeyService, commandService, telemetryService, notificationService); + super(contextKeyService, commandService, telemetryService, notificationService, statusBarService); updateSchema(); @@ -500,21 +500,10 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { weight = KeybindingWeight.ExternalExtension + idx; } - let commandAction = MenuRegistry.getCommand(command); - let precondition = commandAction && commandAction.precondition; - let fullWhen: ContextKeyExpr | undefined; - if (when && precondition) { - fullWhen = ContextKeyExpr.and(precondition, ContextKeyExpr.deserialize(when)); - } else if (when) { - fullWhen = ContextKeyExpr.deserialize(when); - } else if (precondition) { - fullWhen = precondition; - } - let desc: IKeybindingRule2 = { id: command, args, - when: fullWhen, + when: ContextKeyExpr.deserialize(when), weight: weight, primary: KeybindingParser.parseKeybinding(key, OS), mac: mac ? { primary: KeybindingParser.parseKeybinding(mac, OS) } : null, @@ -723,4 +712,4 @@ const keyboardConfiguration: IConfigurationNode = { configurationRegistry.registerConfiguration(keyboardConfiguration); -registerSingleton(IKeybindingService, WorkbenchKeybindingService); +registerSingleton(IKeybindingService, WorkbenchKeybindingService); \ No newline at end of file diff --git a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts index b8fd976c8f..7b50510857 100644 --- a/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts +++ b/src/vs/workbench/services/keybinding/test/electron-browser/keybindingEditing.test.ts @@ -44,7 +44,6 @@ import { TestBackupFileService, TestContextService, TestEditorGroupsService, Tes import { FileService } from 'vs/workbench/services/files/common/fileService'; import { Schemas } from 'vs/base/common/network'; import { DiskFileSystemProvider } from 'vs/workbench/services/files/node/diskFileSystemProvider'; -import { URI } from 'vs/base/common/uri'; interface Modifiers { metaKey?: boolean; @@ -66,7 +65,7 @@ suite('KeybindingsEditing', () => { instantiationService = new TestInstantiationService(); - instantiationService.stub(IEnvironmentService, { appKeybindingsPath: keybindingsFile, settingsResource: URI.file(path.join(testDir, 'settings.json')) }); + instantiationService.stub(IEnvironmentService, { appKeybindingsPath: keybindingsFile, appSettingsPath: path.join(testDir, 'settings.json') }); instantiationService.stub(IConfigurationService, ConfigurationService); instantiationService.stub(IConfigurationService, 'getValue', { 'eol': '\n' }); instantiationService.stub(IConfigurationService, 'onDidUpdateConfiguration', () => { }); diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 75617e9aa0..57ff084478 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -45,21 +45,6 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ readonly onZenModeChange: Event; - /** - * Emits when fullscreen is enabled or disabled. - */ - readonly onFullscreenChange: Event; - - /** - * Emits when centered layout is enabled or disabled. - */ - readonly onCenteredLayoutChange: Event; - - /** - * Emit when panel position changes. - */ - readonly onPanelPositionChange: Event; - /** * Asks the part service if all parts have been fully restored. For editor part * this means that the contents of editors have loaded. diff --git a/src/vs/workbench/services/notification/common/notificationService.ts b/src/vs/workbench/services/notification/common/notificationService.ts index f477cb7281..4621348a50 100644 --- a/src/vs/workbench/services/notification/common/notificationService.ts +++ b/src/vs/workbench/services/notification/common/notificationService.ts @@ -3,17 +3,15 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, INotificationHandle, Severity, NotificationMessage, INotificationActions, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; import { INotificationsModel, NotificationsModel, ChoiceAction } from 'vs/workbench/common/notifications'; -import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; +import { dispose, Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { Event } from 'vs/base/common/event'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IAction } from 'vs/base/common/actions'; export class NotificationService extends Disposable implements INotificationService { - _serviceBrand: ServiceIdentifier; + _serviceBrand: any; private _model: INotificationsModel = this._register(new NotificationsModel()); @@ -28,7 +26,7 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.addNotification({ severity: Severity.Info, message }); + this.model.notify({ severity: Severity.Info, message }); } warn(message: NotificationMessage | NotificationMessage[]): void { @@ -38,7 +36,7 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.addNotification({ severity: Severity.Warning, message }); + this.model.notify({ severity: Severity.Warning, message }); } error(message: NotificationMessage | NotificationMessage[]): void { @@ -48,32 +46,37 @@ export class NotificationService extends Disposable implements INotificationServ return; } - this.model.addNotification({ severity: Severity.Error, message }); + this.model.notify({ severity: Severity.Error, message }); } notify(notification: INotification): INotificationHandle { - return this.model.addNotification(notification); + return this.model.notify(notification); } prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { - const toDispose = new DisposableStore(); + const toDispose: IDisposable[] = []; let choiceClicked = false; let handle: INotificationHandle; // Convert choices into primary/secondary actions - const primaryActions: IAction[] = []; - const secondaryActions: IAction[] = []; + const actions: INotificationActions = { primary: [], secondary: [] }; choices.forEach((choice, index) => { const action = new ChoiceAction(`workbench.dialog.choice.${index}`, choice); if (!choice.isSecondary) { - primaryActions.push(action); + if (!actions.primary) { + actions.primary = []; + } + actions.primary.push(action); } else { - secondaryActions.push(action); + if (!actions.secondary) { + actions.secondary = []; + } + actions.secondary.push(action); } // React to action being clicked - toDispose.add(action.onDidRun(() => { + toDispose.push(action.onDidRun(() => { choiceClicked = true; // Close notification unless we are told to keep open @@ -82,17 +85,16 @@ export class NotificationService extends Disposable implements INotificationServ } })); - toDispose.add(action); + toDispose.push(action); }); // Show notification with actions - const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; handle = this.notify({ severity, message, actions, sticky: options && options.sticky, silent: options && options.silent }); Event.once(handle.onDidClose)(() => { // Cleanup when notification gets disposed - toDispose.dispose(); + dispose(toDispose); // Indicate cancellation to the outside if no action was executed if (options && typeof options.onCancel === 'function' && !choiceClicked) { @@ -102,10 +104,6 @@ export class NotificationService extends Disposable implements INotificationServ return handle; } - - status(message: NotificationMessage, options?: IStatusMessageOptions): IDisposable { - return this.model.showStatusMessage(message, options); - } } registerSingleton(INotificationService, NotificationService, true); \ No newline at end of file diff --git a/src/vs/workbench/services/output/common/outputChannelModel.ts b/src/vs/workbench/services/output/common/outputChannelModel.ts index 49dc1b0f95..73a4db073c 100644 --- a/src/vs/workbench/services/output/common/outputChannelModel.ts +++ b/src/vs/workbench/services/output/common/outputChannelModel.ts @@ -51,10 +51,10 @@ export abstract class AsbtractOutputChannelModelService { export abstract class AbstractFileOutputChannelModel extends Disposable implements IOutputChannelModel { - protected readonly _onDidAppendedContent = this._register(new Emitter()); + protected _onDidAppendedContent = new Emitter(); readonly onDidAppendedContent: Event = this._onDidAppendedContent.event; - protected readonly _onDispose = this._register(new Emitter()); + protected _onDispose = new Emitter(); readonly onDispose: Event = this._onDispose.event; protected modelUpdater: RunOnceScheduler; @@ -96,11 +96,12 @@ export abstract class AbstractFileOutputChannelModel extends Disposable implemen } else { this.model = this.modelService.createModel(content, this.modeService.create(this.mimeType), this.modelUri); this.onModelCreated(this.model); - const disposable = this.model.onWillDispose(() => { + const disposables: IDisposable[] = []; + disposables.push(this.model.onWillDispose(() => { this.onModelWillDispose(this.model); this.model = null; - dispose(disposable); - }); + dispose(disposables); + })); } return this.model; } @@ -339,10 +340,11 @@ export class BufferredOutputChannel extends Disposable implements IOutputChannel private createModel(content: string): ITextModel { const model = this.modelService.createModel(content, this.modeService.create(this.mimeType), this.modelUri); - const disposable = model.onWillDispose(() => { + const disposables: IDisposable[] = []; + disposables.push(model.onWillDispose(() => { this.model = null; - dispose(disposable); - }); + dispose(disposables); + })); return model; } diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 1c2075d893..ecb2429752 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -524,9 +524,9 @@ export class PreferencesService extends Disposable implements IPreferencesServic switch (configurationTarget) { case ConfigurationTarget.USER: case ConfigurationTarget.USER_LOCAL: - return this.environmentService.settingsResource; + return URI.file(this.environmentService.appSettingsPath); case ConfigurationTarget.USER_REMOTE: - return this.environmentService.settingsResource; + return URI.file(this.environmentService.appSettingsPath); case ConfigurationTarget.WORKSPACE: if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { return null; diff --git a/src/vs/workbench/services/progress/browser/localProgressService.ts b/src/vs/workbench/services/progress/browser/localProgressService.ts deleted file mode 100644 index c1b2c3b06a..0000000000 --- a/src/vs/workbench/services/progress/browser/localProgressService.ts +++ /dev/null @@ -1,306 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { Disposable } from 'vs/base/common/lifecycle'; -import * as types from 'vs/base/common/types'; -import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; -import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ILocalProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; - -namespace ProgressState { - - export const enum Type { - None, - Done, - Infinite, - While, - Work - } - - export const None = new class { readonly type = Type.None; }; - export const Done = new class { readonly type = Type.Done; }; - export const Infinite = new class { readonly type = Type.Infinite; }; - - export class While { - readonly type = Type.While; - - constructor( - readonly whilePromise: Promise, - readonly whileStart: number, - readonly whileDelay: number, - ) { } - } - - export class Work { - readonly type = Type.Work; - - constructor( - readonly total: number | undefined, - readonly worked: number | undefined - ) { } - } - - export type State = - typeof None - | typeof Done - | typeof Infinite - | While - | Work; -} - -export abstract class ScopedService extends Disposable { - - constructor( - private viewletService: IViewletService, - private panelService: IPanelService, - private scopeId: string - ) { - super(); - - this.registerListeners(); - } - - registerListeners(): void { - this._register(this.viewletService.onDidViewletOpen(viewlet => this.onScopeOpened(viewlet.getId()))); - this._register(this.panelService.onDidPanelOpen(({ panel }) => this.onScopeOpened(panel.getId()))); - - this._register(this.viewletService.onDidViewletClose(viewlet => this.onScopeClosed(viewlet.getId()))); - this._register(this.panelService.onDidPanelClose(panel => this.onScopeClosed(panel.getId()))); - } - - private onScopeClosed(scopeId: string) { - if (scopeId === this.scopeId) { - this.onScopeDeactivated(); - } - } - - private onScopeOpened(scopeId: string) { - if (scopeId === this.scopeId) { - this.onScopeActivated(); - } - } - - abstract onScopeActivated(): void; - - abstract onScopeDeactivated(): void; -} - -export class ScopedProgressService extends ScopedService implements ILocalProgressService { - - _serviceBrand: ServiceIdentifier; - - private isActive: boolean; - private progressbar: ProgressBar; - private progressState: ProgressState.State = ProgressState.None; - - constructor( - progressbar: ProgressBar, - scopeId: string, - isActive: boolean, - @IViewletService viewletService: IViewletService, - @IPanelService panelService: IPanelService - ) { - super(viewletService, panelService, scopeId); - - this.progressbar = progressbar; - this.isActive = isActive || types.isUndefinedOrNull(scopeId); // If service is unscoped, enable by default - } - - onScopeDeactivated(): void { - this.isActive = false; - } - - onScopeActivated(): void { - this.isActive = true; - - // Return early if progress state indicates that progress is done - if (this.progressState.type === ProgressState.Done.type) { - return; - } - - // Replay Infinite Progress from Promise - if (this.progressState.type === ProgressState.Type.While) { - let delay: number | undefined; - if (this.progressState.whileDelay > 0) { - const remainingDelay = this.progressState.whileDelay - (Date.now() - this.progressState.whileStart); - if (remainingDelay > 0) { - delay = remainingDelay; - } - } - - this.doShowWhile(delay); - } - - // Replay Infinite Progress - else if (this.progressState.type === ProgressState.Type.Infinite) { - this.progressbar.infinite().show(); - } - - // Replay Finite Progress (Total & Worked) - else if (this.progressState.type === ProgressState.Type.Work) { - if (this.progressState.total) { - this.progressbar.total(this.progressState.total).show(); - } - - if (this.progressState.worked) { - this.progressbar.worked(this.progressState.worked).show(); - } - } - } - - show(infinite: true, delay?: number): IProgressRunner; - show(total: number, delay?: number): IProgressRunner; - show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { - - // Sort out Arguments - if (typeof infiniteOrTotal === 'boolean') { - this.progressState = ProgressState.Infinite; - } else { - this.progressState = new ProgressState.Work(infiniteOrTotal, undefined); - } - - // Active: Show Progress - if (this.isActive) { - - // Infinite: Start Progressbar and Show after Delay - if (this.progressState.type === ProgressState.Type.Infinite) { - this.progressbar.infinite().show(delay); - } - - // Finite: Start Progressbar and Show after Delay - else if (this.progressState.type === ProgressState.Type.Work && typeof this.progressState.total === 'number') { - this.progressbar.total(this.progressState.total).show(delay); - } - } - - return { - total: (total: number) => { - this.progressState = new ProgressState.Work( - total, - this.progressState.type === ProgressState.Type.Work ? this.progressState.worked : undefined); - - if (this.isActive) { - this.progressbar.total(total); - } - }, - - worked: (worked: number) => { - - // Verify first that we are either not active or the progressbar has a total set - if (!this.isActive || this.progressbar.hasTotal()) { - this.progressState = new ProgressState.Work( - this.progressState.type === ProgressState.Type.Work ? this.progressState.total : undefined, - this.progressState.type === ProgressState.Type.Work && typeof this.progressState.worked === 'number' ? this.progressState.worked + worked : worked); - - if (this.isActive) { - this.progressbar.worked(worked); - } - } - - // Otherwise the progress bar does not support worked(), we fallback to infinite() progress - else { - this.progressState = ProgressState.Infinite; - this.progressbar.infinite().show(); - } - }, - - done: () => { - this.progressState = ProgressState.Done; - - if (this.isActive) { - this.progressbar.stop().hide(); - } - } - }; - } - - async showWhile(promise: Promise, delay?: number): Promise { - - // Join with existing running promise to ensure progress is accurate - if (this.progressState.type === ProgressState.Type.While) { - promise = Promise.all([promise, this.progressState.whilePromise]); - } - - // Keep Promise in State - this.progressState = new ProgressState.While(promise, delay || 0, Date.now()); - - try { - this.doShowWhile(delay); - - await promise; - } catch (error) { - // ignore - } finally { - - // If this is not the last promise in the list of joined promises, skip this - if (this.progressState.type !== ProgressState.Type.While || this.progressState.whilePromise === promise) { - - // The while promise is either null or equal the promise we last hooked on - this.progressState = ProgressState.None; - - if (this.isActive) { - this.progressbar.stop().hide(); - } - } - } - } - - private doShowWhile(delay?: number): void { - - // Show Progress when active - if (this.isActive) { - this.progressbar.infinite().show(delay); - } - } -} - -export class LocalProgressService implements ILocalProgressService { - - _serviceBrand: ServiceIdentifier; - - constructor(private progressbar: ProgressBar) { } - - show(infinite: true, delay?: number): IProgressRunner; - show(total: number, delay?: number): IProgressRunner; - show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { - if (typeof infiniteOrTotal === 'boolean') { - this.progressbar.infinite().show(delay); - } else { - this.progressbar.total(infiniteOrTotal).show(delay); - } - - return { - total: (total: number) => { - this.progressbar.total(total); - }, - - worked: (worked: number) => { - if (this.progressbar.hasTotal()) { - this.progressbar.worked(worked); - } else { - this.progressbar.infinite().show(); - } - }, - - done: () => { - this.progressbar.stop().hide(); - } - }; - } - - async showWhile(promise: Promise, delay?: number): Promise { - try { - this.progressbar.infinite().show(delay); - - await promise; - } catch (error) { - // ignore - } finally { - this.progressbar.stop().hide(); - } - } -} diff --git a/src/vs/workbench/services/progress/browser/media/progressService.css b/src/vs/workbench/services/progress/browser/media/progressService2.css similarity index 85% rename from src/vs/workbench/services/progress/browser/media/progressService.css rename to src/vs/workbench/services/progress/browser/media/progressService2.css index c7e5960f2b..e4516338b5 100644 --- a/src/vs/workbench/services/progress/browser/media/progressService.css +++ b/src/vs/workbench/services/progress/browser/media/progressService2.css @@ -3,11 +3,11 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.progress { +.monaco-workbench .part.statusbar > .statusbar-item.progress { padding-left: 5px; } -.monaco-workbench .part.statusbar > .items-container > .statusbar-item.progress .spinner-container { +.monaco-workbench .part.statusbar > .statusbar-item.progress .spinner-container { padding-right: 5px; } diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index 80751e844a..f5f09c13ab 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -3,341 +3,294 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import 'vs/css!./media/progressService'; - -import { localize } from 'vs/nls'; -import { IDisposable, dispose, DisposableStore } from 'vs/base/common/lifecycle'; -import { IProgressService, IProgressOptions, IProgressStep, ProgressLocation, IProgress, emptyProgress, Progress, IProgressCompositeOptions, IProgressNotificationOptions } from 'vs/platform/progress/common/progress'; +import { Disposable } from 'vs/base/common/lifecycle'; +import * as types from 'vs/base/common/types'; +import { ProgressBar } from 'vs/base/browser/ui/progressbar/progressbar'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; -import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; -import { timeout } from 'vs/base/common/async'; -import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity'; -import { INotificationService, Severity, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification'; -import { Action } from 'vs/base/common/actions'; -import { Event } from 'vs/base/common/event'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; -import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; -import { attachDialogStyler } from 'vs/platform/theme/common/styler'; -import { IThemeService } from 'vs/platform/theme/common/themeService'; -import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; -import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; -import { EventHelper } from 'vs/base/browser/dom'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; +import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; +import { IProgressService, IProgressRunner } from 'vs/platform/progress/common/progress'; -export class ProgressService implements IProgressService { - _serviceBrand: ServiceIdentifier; +namespace ProgressState { + export const enum Type { + None, + Done, + Infinite, + While, + Work + } - private readonly _stack: [IProgressOptions, Progress][] = []; - private _globalStatusEntry: IDisposable; + export const None = new class { readonly type = Type.None; }; + export const Done = new class { readonly type = Type.Done; }; + export const Infinite = new class { readonly type = Type.Infinite; }; + + export class While { + public readonly type = Type.While; + constructor( + public readonly whilePromise: Promise, + public readonly whileStart: number, + public readonly whileDelay: number, + ) { } + } + + export class Work { + public readonly type = Type.Work; + constructor( + public readonly total: number | undefined, + public readonly worked: number | undefined + ) { } + } + + export type State = + typeof None + | typeof Done + | typeof Infinite + | While + | Work; +} + +export abstract class ScopedService extends Disposable { + + constructor(private viewletService: IViewletService, private panelService: IPanelService, private scopeId: string) { + super(); + + this.registerListeners(); + } + + registerListeners(): void { + this._register(this.viewletService.onDidViewletOpen(viewlet => this.onScopeOpened(viewlet.getId()))); + this._register(this.panelService.onDidPanelOpen(({ panel }) => this.onScopeOpened(panel.getId()))); + + this._register(this.viewletService.onDidViewletClose(viewlet => this.onScopeClosed(viewlet.getId()))); + this._register(this.panelService.onDidPanelClose(panel => this.onScopeClosed(panel.getId()))); + } + + private onScopeClosed(scopeId: string) { + if (scopeId === this.scopeId) { + this.onScopeDeactivated(); + } + } + + private onScopeOpened(scopeId: string) { + if (scopeId === this.scopeId) { + this.onScopeActivated(); + } + } + + abstract onScopeActivated(): void; + + abstract onScopeDeactivated(): void; +} + +export class ScopedProgressService extends ScopedService implements IProgressService { + _serviceBrand: any; + private isActive: boolean; + private progressbar: ProgressBar; + private progressState: ProgressState.State = ProgressState.None; constructor( - @IActivityService private readonly _activityBar: IActivityService, - @IViewletService private readonly _viewletService: IViewletService, - @INotificationService private readonly _notificationService: INotificationService, - @IStatusbarService private readonly _statusbarService: IStatusbarService, - @ILayoutService private readonly _layoutService: ILayoutService, - @IThemeService private readonly _themeService: IThemeService, - @IKeybindingService private readonly _keybindingService: IKeybindingService - ) { } + progressbar: ProgressBar, + scopeId: string, + isActive: boolean, + @IViewletService viewletService: IViewletService, + @IPanelService panelService: IPanelService + ) { + super(viewletService, panelService, scopeId); - withProgress(options: IProgressOptions, task: (progress: IProgress) => Promise, onDidCancel?: () => void): Promise { - const { location } = options; - if (typeof location === 'string') { - const viewlet = this._viewletService.getViewlet(location); - if (viewlet) { - return this._withViewletProgress(location, task, { ...options, location }); - } + this.progressbar = progressbar; + this.isActive = isActive || types.isUndefinedOrNull(scopeId); // If service is unscoped, enable by default + } - return Promise.reject(new Error(`Bad progress location: ${location}`)); + onScopeDeactivated(): void { + this.isActive = false; + } + + onScopeActivated(): void { + this.isActive = true; + + // Return early if progress state indicates that progress is done + if (this.progressState.type === ProgressState.Done.type) { + return; } - switch (location) { - case ProgressLocation.Notification: - return this._withNotificationProgress({ ...options, location }, task, onDidCancel); - case ProgressLocation.Window: - return this._withWindowProgress(options, task); - case ProgressLocation.Explorer: - return this._withViewletProgress('workbench.view.explorer', task, { ...options, location }); - case ProgressLocation.Scm: - return this._withViewletProgress('workbench.view.scm', task, { ...options, location }); - case ProgressLocation.Extensions: - return this._withViewletProgress('workbench.view.extensions', task, { ...options, location }); - case ProgressLocation.Dialog: - return this._withDialogProgress(options, task, onDidCancel); - default: - return Promise.reject(new Error(`Bad progress location: ${location}`)); + // Replay Infinite Progress from Promise + if (this.progressState.type === ProgressState.Type.While) { + let delay: number | undefined; + if (this.progressState.whileDelay > 0) { + const remainingDelay = this.progressState.whileDelay - (Date.now() - this.progressState.whileStart); + if (remainingDelay > 0) { + delay = remainingDelay; + } + } + + this.doShowWhile(delay); + } + + // Replay Infinite Progress + else if (this.progressState.type === ProgressState.Type.Infinite) { + this.progressbar.infinite().show(); + } + + // Replay Finite Progress (Total & Worked) + else if (this.progressState.type === ProgressState.Type.Work) { + if (this.progressState.total) { + this.progressbar.total(this.progressState.total).show(); + } + + if (this.progressState.worked) { + this.progressbar.worked(this.progressState.worked).show(); + } } } - private _withWindowProgress(options: IProgressOptions, callback: (progress: IProgress<{ message?: string }>) => Promise): Promise { - const task: [IProgressOptions, Progress] = [options, new Progress(() => this._updateWindowProgress())]; + show(infinite: true, delay?: number): IProgressRunner; + show(total: number, delay?: number): IProgressRunner; + show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { + // Sort out Arguments + if (typeof infiniteOrTotal === 'boolean') { + this.progressState = ProgressState.Infinite; + } else { + this.progressState = new ProgressState.Work(infiniteOrTotal, undefined); + } - const promise = callback(task[1]); + // Active: Show Progress + if (this.isActive) { - let delayHandle: any = setTimeout(() => { - delayHandle = undefined; - this._stack.unshift(task); - this._updateWindowProgress(); - - // show progress for at least 150ms - Promise.all([ - timeout(150), - promise - ]).finally(() => { - const idx = this._stack.indexOf(task); - this._stack.splice(idx, 1); - this._updateWindowProgress(); - }); - }, 150); - - // cancel delay if promise finishes below 150ms - return promise.finally(() => clearTimeout(delayHandle)); - } - - private _updateWindowProgress(idx: number = 0) { - dispose(this._globalStatusEntry); - - if (idx < this._stack.length) { - const [options, progress] = this._stack[idx]; - - let progressTitle = options.title; - let progressMessage = progress.value && progress.value.message; - let text: string; - let title: string; - - if (progressTitle && progressMessage) { - // : <message> - text = localize('progress.text2', "{0}: {1}", progressTitle, progressMessage); - title = options.source ? localize('progress.title3', "[{0}] {1}: {2}", options.source, progressTitle, progressMessage) : text; - - } else if (progressTitle) { - // <title> - text = progressTitle; - title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressTitle) : text; - - } else if (progressMessage) { - // <message> - text = progressMessage; - title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressMessage) : text; - - } else { - // no title, no message -> no progress. try with next on stack - this._updateWindowProgress(idx + 1); - return; + // Infinite: Start Progressbar and Show after Delay + if (this.progressState.type === ProgressState.Type.Infinite) { + this.progressbar.infinite().show(delay); } - this._globalStatusEntry = this._statusbarService.addEntry({ - text: `$(sync~spin) ${text}`, - tooltip: title - }, 'status.progress', localize('status.progress', "Progress Message"), StatusbarAlignment.LEFT); + // Finite: Start Progressbar and Show after Delay + else if (this.progressState.type === ProgressState.Type.Work && typeof this.progressState.total === 'number') { + this.progressbar.total(this.progressState.total).show(delay); + } + } + + return { + total: (total: number) => { + this.progressState = new ProgressState.Work( + total, + this.progressState.type === ProgressState.Type.Work ? this.progressState.worked : undefined); + + if (this.isActive) { + this.progressbar.total(total); + } + }, + + worked: (worked: number) => { + + // Verify first that we are either not active or the progressbar has a total set + if (!this.isActive || this.progressbar.hasTotal()) { + this.progressState = new ProgressState.Work( + this.progressState.type === ProgressState.Type.Work ? this.progressState.total : undefined, + this.progressState.type === ProgressState.Type.Work && typeof this.progressState.worked === 'number' ? this.progressState.worked + worked : worked); + + if (this.isActive) { + this.progressbar.worked(worked); + } + } + + // Otherwise the progress bar does not support worked(), we fallback to infinite() progress + else { + this.progressState = ProgressState.Infinite; + this.progressbar.infinite().show(); + } + }, + + done: () => { + this.progressState = ProgressState.Done; + + if (this.isActive) { + this.progressbar.stop().hide(); + } + } + }; + } + + async showWhile(promise: Promise<any>, delay?: number): Promise<void> { + + // Join with existing running promise to ensure progress is accurate + if (this.progressState.type === ProgressState.Type.While) { + promise = Promise.all([promise, this.progressState.whilePromise]); + } + + // Keep Promise in State + this.progressState = new ProgressState.While(promise, delay || 0, Date.now()); + + try { + this.doShowWhile(delay); + + await promise; + } catch (error) { + // ignore + } finally { + + // If this is not the last promise in the list of joined promises, skip this + if (this.progressState.type !== ProgressState.Type.While || this.progressState.whilePromise === promise) { + + // The while promise is either null or equal the promise we last hooked on + this.progressState = ProgressState.None; + + if (this.isActive) { + this.progressbar.stop().hide(); + } + } } } - private _withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { - const toDispose = new DisposableStore(); + private doShowWhile(delay?: number): void { - const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { - if (!message) { - return undefined; // we need a message at least - } - - const primaryActions = options.primaryActions ? Array.from(options.primaryActions) : []; - const secondaryActions = options.secondaryActions ? Array.from(options.secondaryActions) : []; - if (options.cancellable) { - const cancelAction = new class extends Action { - constructor() { - super('progress.cancel', localize('cancel', "Cancel"), undefined, true); - } - - run(): Promise<any> { - if (typeof onDidCancel === 'function') { - onDidCancel(); - } - - return Promise.resolve(undefined); - } - }; - toDispose.add(cancelAction); - - primaryActions.push(cancelAction); - } - - const actions: INotificationActions = { primary: primaryActions, secondary: secondaryActions }; - const handle = this._notificationService.notify({ - severity: Severity.Info, - message, - source: options.source, - actions - }); - - updateProgress(handle, increment); - - Event.once(handle.onDidClose)(() => { - toDispose.dispose(); - }); - - return handle; - }; - - const updateProgress = (notification: INotificationHandle, increment?: number): void => { - if (typeof increment === 'number' && increment >= 0) { - notification.progress.total(100); // always percentage based - notification.progress.worked(increment); - } else { - notification.progress.infinite(); - } - }; - - let handle: INotificationHandle | undefined; - const updateNotification = (message?: string, increment?: number): void => { - if (!handle) { - handle = createNotification(message, increment); - } else { - if (typeof message === 'string') { - let newMessage: string; - if (typeof options.title === 'string') { - newMessage = `${options.title}: ${message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932) - } else { - newMessage = message; - } - - handle.updateMessage(newMessage); - } - - if (typeof increment === 'number') { - updateProgress(handle, increment); - } - } - }; - - // Show initially - updateNotification(options.title); - - // Update based on progress - const promise = callback({ - report: progress => { - updateNotification(progress.message, progress.increment); - } - }); - - // Show progress for at least 800ms and then hide once done or canceled - Promise.all([timeout(800), promise]).finally(() => { - if (handle) { - handle.close(); - } - }); - - return promise; - } - - private _withViewletProgress<P extends Promise<R>, R = unknown>(viewletId: string, task: (progress: IProgress<{ message?: string }>) => P, options: IProgressCompositeOptions): P { - const promise = task(emptyProgress); - - // show in viewlet - const viewletProgress = this._viewletService.getProgressIndicator(viewletId); - if (viewletProgress) { - viewletProgress.showWhile(promise, options.delay); + // Show Progress when active + if (this.isActive) { + this.progressbar.infinite().show(delay); } - - // show activity bar - let activityProgress: IDisposable; - let delayHandle: any = setTimeout(() => { - delayHandle = undefined; - - const handle = this._activityBar.showActivity( - viewletId, - new ProgressBadge(() => ''), - 'progress-badge', - 100 - ); - - const startTimeVisible = Date.now(); - const minTimeVisible = 300; - activityProgress = { - dispose() { - const d = Date.now() - startTimeVisible; - if (d < minTimeVisible) { - // should at least show for Nms - setTimeout(() => handle.dispose(), minTimeVisible - d); - } else { - // shown long enough - handle.dispose(); - } - } - }; - }, options.delay || 300); - - promise.finally(() => { - clearTimeout(delayHandle); - dispose(activityProgress); - }); - - return promise; - } - - private _withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { - const disposables = new DisposableStore(); - const allowableCommands = [ - 'workbench.action.quit', - 'workbench.action.reloadWindow' - ]; - - let dialog: Dialog; - - const createDialog = (message: string) => { - dialog = new Dialog( - this._layoutService.container, - message, - [options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], - { - type: 'pending', - keyEventProcessor: (event: StandardKeyboardEvent) => { - const resolved = this._keybindingService.softDispatch(event, this._layoutService.container); - if (resolved && resolved.commandId) { - if (allowableCommands.indexOf(resolved.commandId) === -1) { - EventHelper.stop(event, true); - } - } - } - } - ); - - disposables.add(dialog); - disposables.add(attachDialogStyler(dialog, this._themeService)); - - dialog.show().then(() => { - if (typeof onDidCancel === 'function') { - onDidCancel(); - } - - dispose(dialog); - }); - - return dialog; - }; - - const updateDialog = (message?: string) => { - if (message && !dialog) { - dialog = createDialog(message); - } else if (message) { - dialog.updateMessage(message); - } - }; - - const promise = task({ - report: progress => { - updateDialog(progress.message); - } - }); - - promise.finally(() => { - dispose(disposables); - }); - - return promise; } } -registerSingleton(IProgressService, ProgressService, true); +export class ProgressService implements IProgressService { + + _serviceBrand: any; + + constructor(private progressbar: ProgressBar) { } + + show(infinite: true, delay?: number): IProgressRunner; + show(total: number, delay?: number): IProgressRunner; + show(infiniteOrTotal: true | number, delay?: number): IProgressRunner { + if (typeof infiniteOrTotal === 'boolean') { + this.progressbar.infinite().show(delay); + } else { + this.progressbar.total(infiniteOrTotal).show(delay); + } + + return { + total: (total: number) => { + this.progressbar.total(total); + }, + + worked: (worked: number) => { + if (this.progressbar.hasTotal()) { + this.progressbar.worked(worked); + } else { + this.progressbar.infinite().show(); + } + }, + + done: () => { + this.progressbar.stop().hide(); + } + }; + } + + async showWhile(promise: Promise<any>, delay?: number): Promise<void> { + try { + this.progressbar.infinite().show(delay); + + await promise; + } catch (error) { + // ignore + } finally { + this.progressbar.stop().hide(); + } + } +} diff --git a/src/vs/workbench/services/progress/browser/progressService2.ts b/src/vs/workbench/services/progress/browser/progressService2.ts new file mode 100644 index 0000000000..1e516d069a --- /dev/null +++ b/src/vs/workbench/services/progress/browser/progressService2.ts @@ -0,0 +1,344 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import 'vs/css!./media/progressService2'; + +import { localize } from 'vs/nls'; +import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IProgressService2, IProgressOptions, IProgressStep, ProgressLocation, IProgress, emptyProgress, Progress, IProgressNotificationOptions } from 'vs/platform/progress/common/progress'; +import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; +import { StatusbarAlignment, IStatusbarService } from 'vs/platform/statusbar/common/statusbar'; +import { timeout } from 'vs/base/common/async'; +import { ProgressBadge, IActivityService } from 'vs/workbench/services/activity/common/activity'; +import { INotificationService, Severity, INotificationHandle, INotificationActions } from 'vs/platform/notification/common/notification'; +import { Action } from 'vs/base/common/actions'; +import { Event } from 'vs/base/common/event'; +import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; +import { Dialog } from 'vs/base/browser/ui/dialog/dialog'; +import { attachDialogStyler } from 'vs/platform/theme/common/styler'; +import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; +import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; +import { EventHelper } from 'vs/base/browser/dom'; + +export class ProgressService2 implements IProgressService2 { + + _serviceBrand: any; + + private readonly _stack: [IProgressOptions, Progress<IProgressStep>][] = []; + private _globalStatusEntry: IDisposable; + + constructor( + @IActivityService private readonly _activityBar: IActivityService, + @IViewletService private readonly _viewletService: IViewletService, + @INotificationService private readonly _notificationService: INotificationService, + @IStatusbarService private readonly _statusbarService: IStatusbarService, + @ILayoutService private readonly _layoutService: ILayoutService, + @IThemeService private readonly _themeService: IThemeService, + @IKeybindingService private readonly _keybindingService: IKeybindingService + ) { } + + withProgress<R = unknown>(options: IProgressOptions, task: (progress: IProgress<IProgressStep>) => Promise<R>, onDidCancel?: () => void): Promise<R> { + + const { location } = options; + if (typeof location === 'string') { + const viewlet = this._viewletService.getViewlet(location); + if (viewlet) { + return this._withViewletProgress(location, task); + } + return Promise.reject(new Error(`Bad progress location: ${location}`)); + } + + switch (location) { + case ProgressLocation.Notification: + return this._withNotificationProgress({ ...options, location: ProgressLocation.Notification }, task, onDidCancel); + case ProgressLocation.Window: + return this._withWindowProgress(options, task); + case ProgressLocation.Explorer: + return this._withViewletProgress('workbench.view.explorer', task); + case ProgressLocation.Scm: + return this._withViewletProgress('workbench.view.scm', task); + case ProgressLocation.Extensions: + return this._withViewletProgress('workbench.view.extensions', task); + case ProgressLocation.Dialog: + return this._withDialogProgress(options, task, onDidCancel); + default: + return Promise.reject(new Error(`Bad progress location: ${location}`)); + } + } + + private _withWindowProgress<R = unknown>(options: IProgressOptions, callback: (progress: IProgress<{ message?: string }>) => Promise<R>): Promise<R> { + + const task: [IProgressOptions, Progress<IProgressStep>] = [options, new Progress<IProgressStep>(() => this._updateWindowProgress())]; + + const promise = callback(task[1]); + + let delayHandle: any = setTimeout(() => { + delayHandle = undefined; + this._stack.unshift(task); + this._updateWindowProgress(); + + // show progress for at least 150ms + Promise.all([ + timeout(150), + promise + ]).finally(() => { + const idx = this._stack.indexOf(task); + this._stack.splice(idx, 1); + this._updateWindowProgress(); + }); + + }, 150); + + // cancel delay if promise finishes below 150ms + return promise.finally(() => clearTimeout(delayHandle)); + } + + private _updateWindowProgress(idx: number = 0) { + + dispose(this._globalStatusEntry); + + if (idx < this._stack.length) { + + const [options, progress] = this._stack[idx]; + + let progressTitle = options.title; + let progressMessage = progress.value && progress.value.message; + let text: string; + let title: string; + + if (progressTitle && progressMessage) { + // <title>: <message> + text = localize('progress.text2', "{0}: {1}", progressTitle, progressMessage); + title = options.source ? localize('progress.title3', "[{0}] {1}: {2}", options.source, progressTitle, progressMessage) : text; + + } else if (progressTitle) { + // <title> + text = progressTitle; + title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressTitle) : text; + + } else if (progressMessage) { + // <message> + text = progressMessage; + title = options.source ? localize('progress.title2', "[{0}]: {1}", options.source, progressMessage) : text; + + } else { + // no title, no message -> no progress. try with next on stack + this._updateWindowProgress(idx + 1); + return; + } + + this._globalStatusEntry = this._statusbarService.addEntry({ + text: `$(sync~spin) ${text}`, + tooltip: title + }, StatusbarAlignment.LEFT); + } + } + + private _withNotificationProgress<P extends Promise<R>, R = unknown>(options: IProgressNotificationOptions, callback: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { + const toDispose: IDisposable[] = []; + + const createNotification = (message: string | undefined, increment?: number): INotificationHandle | undefined => { + if (!message) { + return undefined; // we need a message at least + } + + const actions: INotificationActions = { primary: options.primaryActions || [], secondary: options.secondaryActions || [] }; + if (options.cancellable) { + const cancelAction = new class extends Action { + constructor() { + super('progress.cancel', localize('cancel', "Cancel"), undefined, true); + } + + run(): Promise<any> { + if (typeof onDidCancel === 'function') { + onDidCancel(); + } + + return Promise.resolve(undefined); + } + }; + toDispose.push(cancelAction); + + actions.primary!.push(cancelAction); + } + + const handle = this._notificationService.notify({ + severity: Severity.Info, + message, + source: options.source, + actions + }); + + updateProgress(handle, increment); + + Event.once(handle.onDidClose)(() => { + dispose(toDispose); + }); + + return handle; + }; + + const updateProgress = (notification: INotificationHandle, increment?: number): void => { + if (typeof increment === 'number' && increment >= 0) { + notification.progress.total(100); // always percentage based + notification.progress.worked(increment); + } else { + notification.progress.infinite(); + } + }; + + let handle: INotificationHandle | undefined; + const updateNotification = (message?: string, increment?: number): void => { + if (!handle) { + handle = createNotification(message, increment); + } else { + if (typeof message === 'string') { + let newMessage: string; + if (typeof options.title === 'string') { + newMessage = `${options.title}: ${message}`; // always prefix with overall title if we have it (https://github.com/Microsoft/vscode/issues/50932) + } else { + newMessage = message; + } + + handle.updateMessage(newMessage); + } + + if (typeof increment === 'number') { + updateProgress(handle, increment); + } + } + }; + + // Show initially + updateNotification(options.title); + + // Update based on progress + const p = callback({ + report: progress => { + updateNotification(progress.message, progress.increment); + } + }); + + // Show progress for at least 800ms and then hide once done or canceled + Promise.all([timeout(800), p]).finally(() => { + if (handle) { + handle.close(); + } + }); + + return p; + } + + private _withViewletProgress<P extends Promise<R>, R = unknown>(viewletId: string, task: (progress: IProgress<{ message?: string }>) => P): P { + + const promise = task(emptyProgress); + + // show in viewlet + const viewletProgress = this._viewletService.getProgressIndicator(viewletId); + if (viewletProgress) { + viewletProgress.showWhile(promise); + } + + // show activity bar + let activityProgress: IDisposable; + let delayHandle: any = setTimeout(() => { + delayHandle = undefined; + const handle = this._activityBar.showActivity( + viewletId, + new ProgressBadge(() => ''), + 'progress-badge', + 100 + ); + const startTimeVisible = Date.now(); + const minTimeVisible = 300; + activityProgress = { + dispose() { + const d = Date.now() - startTimeVisible; + if (d < minTimeVisible) { + // should at least show for Nms + setTimeout(() => handle.dispose(), minTimeVisible - d); + } else { + // shown long enough + handle.dispose(); + } + } + }; + }, 300); + + const onDone = () => { + clearTimeout(delayHandle); + dispose(activityProgress); + }; + + promise.then(onDone, onDone); + return promise; + } + + private _withDialogProgress<P extends Promise<R>, R = unknown>(options: IProgressOptions, task: (progress: IProgress<{ message?: string, increment?: number }>) => P, onDidCancel?: () => void): P { + const disposables: IDisposable[] = []; + const allowableCommands = [ + 'workbench.action.quit', + 'workbench.action.reloadWindow' + ]; + + let dialog: Dialog; + + const createDialog = (message: string) => { + dialog = new Dialog( + this._layoutService.container, + message, + [options.cancellable ? localize('cancel', "Cancel") : localize('dismiss', "Dismiss")], + { + type: 'pending', + keyEventProcessor: (event: StandardKeyboardEvent) => { + const resolved = this._keybindingService.softDispatch(event, this._layoutService.container); + if (resolved && resolved.commandId) { + if (allowableCommands.indexOf(resolved.commandId) === -1) { + EventHelper.stop(event, true); + } + } + } + } + ); + + disposables.push(dialog); + disposables.push(attachDialogStyler(dialog, this._themeService)); + + dialog.show().then(() => { + if (typeof onDidCancel === 'function') { + onDidCancel(); + } + + dispose(dialog); + }); + + return dialog; + }; + + const updateDialog = (message?: string) => { + if (message && !dialog) { + dialog = createDialog(message); + } else if (message) { + dialog.updateMessage(message); + } + }; + + const p = task({ + report: progress => { + updateDialog(progress.message); + } + }); + + p.finally(() => { + dispose(disposables); + }); + + return p; + } +} + +registerSingleton(IProgressService2, ProgressService2, true); diff --git a/src/vs/workbench/services/progress/test/localProgressService.test.ts b/src/vs/workbench/services/progress/test/progressService.test.ts similarity index 99% rename from src/vs/workbench/services/progress/test/localProgressService.test.ts rename to src/vs/workbench/services/progress/test/progressService.test.ts index 367d6c92ac..f0dc396eae 100644 --- a/src/vs/workbench/services/progress/test/localProgressService.test.ts +++ b/src/vs/workbench/services/progress/test/progressService.test.ts @@ -6,7 +6,7 @@ import * as assert from 'assert'; import { IAction, IActionViewItem } from 'vs/base/common/actions'; import { IEditorControl } from 'vs/workbench/common/editor'; -import { ScopedProgressService, ScopedService } from 'vs/workbench/services/progress/browser/localProgressService'; +import { ScopedProgressService, ScopedService } from 'vs/workbench/services/progress/browser/progressService'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; import { IViewlet } from 'vs/workbench/common/viewlet'; diff --git a/src/vs/workbench/services/search/node/searchService.ts b/src/vs/workbench/services/search/node/searchService.ts index 994c32f1e8..e39184d324 100644 --- a/src/vs/workbench/services/search/node/searchService.ts +++ b/src/vs/workbench/services/search/node/searchService.ts @@ -13,6 +13,7 @@ import { keys, ResourceMap, values } from 'vs/base/common/map'; import { Schemas } from 'vs/base/common/network'; import { StopWatch } from 'vs/base/common/stopwatch'; import { URI as uri } from 'vs/base/common/uri'; +import * as pfs from 'vs/base/node/pfs'; import { getNextTickChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client, IIPCOptions } from 'vs/base/parts/ipc/node/ipc.cp'; import { IModelService } from 'vs/editor/common/services/modelService'; @@ -424,7 +425,6 @@ export class DiskSearch implements ISearchResultProvider { searchDebug: IDebugParams | undefined, @ILogService private readonly logService: ILogService, @IConfigurationService private readonly configService: IConfigurationService, - @IFileService private readonly fileService: IFileService ) { const timeout = this.configService.getValue<ISearchConfiguration>().search.maintainFileSearchCache ? Number.MAX_VALUE : @@ -465,7 +465,7 @@ export class DiskSearch implements ISearchResultProvider { textSearch(query: ITextQuery, onProgress?: (p: ISearchProgressItem) => void, token?: CancellationToken): Promise<ISearchComplete> { const folderQueries = query.folderQueries || []; - return Promise.all(folderQueries.map(q => this.fileService.exists(q.folder))) + return Promise.all(folderQueries.map(q => q.folder.scheme === Schemas.file && pfs.exists(q.folder.fsPath))) .then(exists => { if (token && token.isCancellationRequested) { throw canceled(); @@ -480,7 +480,7 @@ export class DiskSearch implements ISearchResultProvider { fileSearch(query: IFileQuery, token?: CancellationToken): Promise<ISearchComplete> { const folderQueries = query.folderQueries || []; - return Promise.all(folderQueries.map(q => this.fileService.exists(q.folder))) + return Promise.all(folderQueries.map(q => q.folder.scheme === Schemas.file && pfs.exists(q.folder.fsPath))) .then(exists => { if (token && token.isCancellationRequested) { throw canceled(); diff --git a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts index aa47e093f1..6e25f6ffd3 100644 --- a/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/electron-browser/telemetryService.ts @@ -37,7 +37,7 @@ export class TelemetryService extends Disposable implements ITelemetryService { const channel = sharedProcessService.getChannel('telemetryAppender'); const config: ITelemetryServiceConfig = { appender: combinedAppender(new TelemetryAppenderClient(channel), new LogAppender(logService)), - commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath, environmentService.configuration.remoteAuthority), + commonProperties: resolveWorkbenchCommonProperties(storageService, productService.commit, productService.version, environmentService.configuration.machineId, environmentService.installSourcePath), piiPaths: [environmentService.appRoot, environmentService.extensionsPath] }; diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts deleted file mode 100644 index 6f535e52e1..0000000000 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ /dev/null @@ -1,519 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import * as nls from 'vs/nls'; -import * as dom from 'vs/base/browser/dom'; -import { Color } from 'vs/base/common/color'; -import { onUnexpectedError } from 'vs/base/common/errors'; -import { Emitter, Event } from 'vs/base/common/event'; -import * as resources from 'vs/base/common/resources'; -import * as types from 'vs/base/common/types'; -import { URI } from 'vs/base/common/uri'; -import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token'; -import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRegistry } from 'vs/editor/common/modes'; -import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; -import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { ILogService } from 'vs/platform/log/common/log'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; -import { IEmbeddedLanguagesMap, ITMSyntaxExtensionPoint, TokenTypesContribution, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; -import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; -import { ITokenColorizationRule, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IEmbeddedLanguagesMap as IEmbeddedLanguagesMap2, IGrammar, ITokenTypeMap, Registry, StackElement, StandardTokenType, RegistryOptions, IRawGrammar } from 'vscode-textmate'; -import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; - -export class TMScopeRegistry extends Disposable { - - private _scopeNameToLanguageRegistration: { [scopeName: string]: TMLanguageRegistration; }; - private _encounteredLanguages: boolean[]; - - private readonly _onDidEncounterLanguage = this._register(new Emitter<LanguageId>()); - public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; - - constructor() { - super(); - this.reset(); - } - - public reset(): void { - this._scopeNameToLanguageRegistration = Object.create(null); - this._encounteredLanguages = []; - } - - public register(scopeName: string, grammarLocation: URI, embeddedLanguages?: IEmbeddedLanguagesMap, tokenTypes?: TokenTypesContribution): void { - if (this._scopeNameToLanguageRegistration[scopeName]) { - const existingRegistration = this._scopeNameToLanguageRegistration[scopeName]; - if (!resources.isEqual(existingRegistration.grammarLocation, grammarLocation)) { - console.warn( - `Overwriting grammar scope name to file mapping for scope ${scopeName}.\n` + - `Old grammar file: ${existingRegistration.grammarLocation.toString()}.\n` + - `New grammar file: ${grammarLocation.toString()}` - ); - } - } - this._scopeNameToLanguageRegistration[scopeName] = new TMLanguageRegistration(scopeName, grammarLocation, embeddedLanguages, tokenTypes); - } - - public getLanguageRegistration(scopeName: string): TMLanguageRegistration { - return this._scopeNameToLanguageRegistration[scopeName] || null; - } - - public getGrammarLocation(scopeName: string): URI | null { - let data = this.getLanguageRegistration(scopeName); - return data ? data.grammarLocation : null; - } - - /** - * To be called when tokenization found/hit an embedded language. - */ - public onEncounteredLanguage(languageId: LanguageId): void { - if (!this._encounteredLanguages[languageId]) { - this._encounteredLanguages[languageId] = true; - this._onDidEncounterLanguage.fire(languageId); - } - } -} - -export class TMLanguageRegistration { - _topLevelScopeNameDataBrand: void; - - readonly scopeName: string; - readonly grammarLocation: URI; - readonly embeddedLanguages: IEmbeddedLanguagesMap; - readonly tokenTypes: ITokenTypeMap; - - constructor(scopeName: string, grammarLocation: URI, embeddedLanguages: IEmbeddedLanguagesMap | undefined, tokenTypes: TokenTypesContribution | undefined) { - this.scopeName = scopeName; - this.grammarLocation = grammarLocation; - - // embeddedLanguages handling - this.embeddedLanguages = Object.create(null); - - if (embeddedLanguages) { - // If embeddedLanguages are configured, fill in `this._embeddedLanguages` - let scopes = Object.keys(embeddedLanguages); - for (let i = 0, len = scopes.length; i < len; i++) { - let scope = scopes[i]; - let language = embeddedLanguages[scope]; - if (typeof language !== 'string') { - // never hurts to be too careful - continue; - } - this.embeddedLanguages[scope] = language; - } - } - - this.tokenTypes = Object.create(null); - if (tokenTypes) { - // If tokenTypes is configured, fill in `this._tokenTypes` - const scopes = Object.keys(tokenTypes); - for (const scope of scopes) { - const tokenType = tokenTypes[scope]; - switch (tokenType) { - case 'string': - this.tokenTypes[scope] = StandardTokenType.String; - break; - case 'other': - this.tokenTypes[scope] = StandardTokenType.Other; - break; - case 'comment': - this.tokenTypes[scope] = StandardTokenType.Comment; - break; - } - } - } - } -} - -interface ICreateGrammarResult { - languageId: LanguageId; - grammar: IGrammar; - initialState: StackElement; - containsEmbeddedLanguages: boolean; -} - -export abstract class AbstractTextMateService extends Disposable implements ITextMateService { - public _serviceBrand: any; - - private readonly _onDidEncounterLanguage: Emitter<LanguageId> = this._register(new Emitter<LanguageId>()); - public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; - - private readonly _styleElement: HTMLStyleElement; - private readonly _createdModes: string[]; - - protected _scopeRegistry: TMScopeRegistry; - private _injections: { [scopeName: string]: string[]; }; - private _injectedEmbeddedLanguages: { [scopeName: string]: IEmbeddedLanguagesMap[]; }; - protected _languageToScope: Map<string, string>; - private _grammarRegistry: Promise<[Registry, StackElement]> | null; - private _tokenizersRegistrations: IDisposable[]; - private _currentTokenColors: ITokenColorizationRule[] | null; - private _themeListener: IDisposable | null; - - constructor( - @IModeService private readonly _modeService: IModeService, - @IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService, - @IFileService private readonly _fileService: IFileService, - @INotificationService private readonly _notificationService: INotificationService, - @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService - ) { - super(); - this._styleElement = dom.createStyleSheet(); - this._styleElement.className = 'vscode-tokens-styles'; - this._createdModes = []; - this._scopeRegistry = new TMScopeRegistry(); - this._scopeRegistry.onDidEncounterLanguage((language) => this._onDidEncounterLanguage.fire(language)); - this._injections = {}; - this._injectedEmbeddedLanguages = {}; - this._languageToScope = new Map<string, string>(); - this._grammarRegistry = null; - this._tokenizersRegistrations = []; - this._currentTokenColors = null; - this._themeListener = null; - - grammarsExtPoint.setHandler((extensions) => { - this._scopeRegistry.reset(); - this._injections = {}; - this._injectedEmbeddedLanguages = {}; - this._languageToScope = new Map<string, string>(); - this._grammarRegistry = null; - this._tokenizersRegistrations = dispose(this._tokenizersRegistrations); - this._currentTokenColors = null; - if (this._themeListener) { - this._themeListener.dispose(); - this._themeListener = null; - } - - for (const extension of extensions) { - let grammars = extension.value; - for (const grammar of grammars) { - this._handleGrammarExtensionPointUser(extension.description.extensionLocation, grammar, extension.collector); - } - } - - for (const createMode of this._createdModes) { - this._registerDefinitionIfAvailable(createMode); - } - }); - - // Generate some color map until the grammar registry is loaded - let colorTheme = this._themeService.getColorTheme(); - let defaultForeground: Color = Color.transparent; - let defaultBackground: Color = Color.transparent; - for (let i = 0, len = colorTheme.tokenColors.length; i < len; i++) { - let rule = colorTheme.tokenColors[i]; - if (!rule.scope && rule.settings) { - if (rule.settings.foreground) { - defaultForeground = Color.fromHex(rule.settings.foreground); - } - if (rule.settings.background) { - defaultBackground = Color.fromHex(rule.settings.background); - } - } - } - TokenizationRegistry.setColorMap([null!, defaultForeground, defaultBackground]); - - this._modeService.onDidCreateMode((mode) => { - let modeId = mode.getId(); - this._createdModes.push(modeId); - this._registerDefinitionIfAvailable(modeId); - }); - } - - private _registerDefinitionIfAvailable(modeId: string): void { - if (this._languageToScope.has(modeId)) { - const promise = this._createGrammar(modeId).then((r) => { - return new TMTokenization(this._scopeRegistry, r.languageId, r.grammar, r.initialState, r.containsEmbeddedLanguages, this._notificationService, this._configurationService); - }, e => { - onUnexpectedError(e); - return null; - }); - this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, promise)); - } - } - - protected _getRegistryOptions(parseRawGrammar: (content: string, filePath: string) => IRawGrammar): RegistryOptions { - return { - loadGrammar: async (scopeName: string) => { - const location = this._scopeRegistry.getGrammarLocation(scopeName); - if (!location) { - this._logService.trace(`No grammar found for scope ${scopeName}`); - return null; - } - try { - const content = await this._fileService.readFile(location); - return parseRawGrammar(content.value.toString(), location.path); - } catch (e) { - this._logService.error(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e); - return null; - } - }, - getInjections: (scopeName: string) => { - const scopeParts = scopeName.split('.'); - let injections: string[] = []; - for (let i = 1; i <= scopeParts.length; i++) { - const subScopeName = scopeParts.slice(0, i).join('.'); - injections = [...injections, ...(this._injections[subScopeName] || [])]; - } - return injections; - } - }; - } - - private async _createGrammarRegistry(): Promise<[Registry, StackElement]> { - const { Registry, INITIAL, parseRawGrammar } = await this._loadVSCodeTextmate(); - const grammarRegistry = new Registry(this._getRegistryOptions(parseRawGrammar)); - this._updateTheme(grammarRegistry); - this._themeListener = this._themeService.onDidColorThemeChange((e) => this._updateTheme(grammarRegistry)); - return <[Registry, StackElement]>[grammarRegistry, INITIAL]; - } - - private _getOrCreateGrammarRegistry(): Promise<[Registry, StackElement]> { - if (!this._grammarRegistry) { - this._grammarRegistry = this._createGrammarRegistry(); - } - return this._grammarRegistry; - } - - private static _toColorMap(colorMap: string[]): Color[] { - let result: Color[] = [null!]; - for (let i = 1, len = colorMap.length; i < len; i++) { - result[i] = Color.fromHex(colorMap[i]); - } - return result; - } - - private _updateTheme(grammarRegistry: Registry): void { - let colorTheme = this._themeService.getColorTheme(); - if (!this.compareTokenRules(colorTheme.tokenColors)) { - return; - } - grammarRegistry.setTheme({ name: colorTheme.label, settings: colorTheme.tokenColors }); - let colorMap = AbstractTextMateService._toColorMap(grammarRegistry.getColorMap()); - let cssRules = generateTokensCSSForColorMap(colorMap); - this._styleElement.innerHTML = cssRules; - TokenizationRegistry.setColorMap(colorMap); - } - - private compareTokenRules(newRules: ITokenColorizationRule[]): boolean { - let currRules = this._currentTokenColors; - this._currentTokenColors = newRules; - if (!newRules || !currRules || newRules.length !== currRules.length) { - return true; - } - for (let i = newRules.length - 1; i >= 0; i--) { - let r1 = newRules[i]; - let r2 = currRules[i]; - if (r1.scope !== r2.scope) { - return true; - } - let s1 = r1.settings; - let s2 = r2.settings; - if (s1 && s2) { - if (s1.fontStyle !== s2.fontStyle || s1.foreground !== s2.foreground || s1.background !== s2.background) { - return true; - } - } else if (!s1 || !s2) { - return true; - } - } - return false; - } - - private _handleGrammarExtensionPointUser(extensionLocation: URI, syntax: ITMSyntaxExtensionPoint, collector: ExtensionMessageCollector): void { - if (syntax.language && ((typeof syntax.language !== 'string') || !this._modeService.isRegisteredMode(syntax.language))) { - collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", grammarsExtPoint.name, String(syntax.language))); - return; - } - if (!syntax.scopeName || (typeof syntax.scopeName !== 'string')) { - collector.error(nls.localize('invalid.scopeName', "Expected string in `contributes.{0}.scopeName`. Provided value: {1}", grammarsExtPoint.name, String(syntax.scopeName))); - return; - } - if (!syntax.path || (typeof syntax.path !== 'string')) { - collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", grammarsExtPoint.name, String(syntax.path))); - return; - } - if (syntax.injectTo && (!Array.isArray(syntax.injectTo) || syntax.injectTo.some(scope => typeof scope !== 'string'))) { - collector.error(nls.localize('invalid.injectTo', "Invalid value in `contributes.{0}.injectTo`. Must be an array of language scope names. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.injectTo))); - return; - } - if (syntax.embeddedLanguages && !types.isObject(syntax.embeddedLanguages)) { - collector.error(nls.localize('invalid.embeddedLanguages', "Invalid value in `contributes.{0}.embeddedLanguages`. Must be an object map from scope name to language. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.embeddedLanguages))); - return; - } - - if (syntax.tokenTypes && !types.isObject(syntax.tokenTypes)) { - collector.error(nls.localize('invalid.tokenTypes', "Invalid value in `contributes.{0}.tokenTypes`. Must be an object map from scope name to token type. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.tokenTypes))); - return; - } - - const grammarLocation = resources.joinPath(extensionLocation, syntax.path); - if (!resources.isEqualOrParent(grammarLocation, extensionLocation)) { - collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", grammarsExtPoint.name, grammarLocation.path, extensionLocation.path)); - } - - this._scopeRegistry.register(syntax.scopeName, grammarLocation, syntax.embeddedLanguages, syntax.tokenTypes); - - if (syntax.injectTo) { - for (let injectScope of syntax.injectTo) { - let injections = this._injections[injectScope]; - if (!injections) { - this._injections[injectScope] = injections = []; - } - injections.push(syntax.scopeName); - } - - if (syntax.embeddedLanguages) { - for (let injectScope of syntax.injectTo) { - let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope]; - if (!injectedEmbeddedLanguages) { - this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = []; - } - injectedEmbeddedLanguages.push(syntax.embeddedLanguages); - } - } - } - - let modeId = syntax.language; - if (modeId) { - this._languageToScope.set(modeId, syntax.scopeName); - } - } - - private _resolveEmbeddedLanguages(embeddedLanguages: IEmbeddedLanguagesMap): IEmbeddedLanguagesMap2 { - let scopes = Object.keys(embeddedLanguages); - let result: IEmbeddedLanguagesMap2 = Object.create(null); - for (let i = 0, len = scopes.length; i < len; i++) { - let scope = scopes[i]; - let language = embeddedLanguages[scope]; - let languageIdentifier = this._modeService.getLanguageIdentifier(language); - if (languageIdentifier) { - result[scope] = languageIdentifier.id; - } - } - return result; - } - - public async createGrammar(modeId: string): Promise<IGrammar> { - const { grammar } = await this._createGrammar(modeId); - return grammar; - } - - private async _createGrammar(modeId: string): Promise<ICreateGrammarResult> { - const scopeName = this._languageToScope.get(modeId); - if (typeof scopeName !== 'string') { - // No TM grammar defined - return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); - } - const languageRegistration = this._scopeRegistry.getLanguageRegistration(scopeName); - if (!languageRegistration) { - // No TM grammar defined - return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); - } - let embeddedLanguages = this._resolveEmbeddedLanguages(languageRegistration.embeddedLanguages); - let rawInjectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName]; - if (rawInjectedEmbeddedLanguages) { - let injectedEmbeddedLanguages: IEmbeddedLanguagesMap2[] = rawInjectedEmbeddedLanguages.map(this._resolveEmbeddedLanguages.bind(this)); - for (const injected of injectedEmbeddedLanguages) { - for (const scope of Object.keys(injected)) { - embeddedLanguages[scope] = injected[scope]; - } - } - } - - let languageId = this._modeService.getLanguageIdentifier(modeId)!.id; - let containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0); - - const [grammarRegistry, initialState] = await this._getOrCreateGrammarRegistry(); - const grammar = await grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: languageRegistration.tokenTypes }); - return { - languageId: languageId, - grammar: grammar, - initialState: initialState, - containsEmbeddedLanguages: containsEmbeddedLanguages - }; - } - - protected abstract _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')>; -} - -class TMTokenization implements ITokenizationSupport { - - private readonly _scopeRegistry: TMScopeRegistry; - private readonly _languageId: LanguageId; - private readonly _grammar: IGrammar; - private readonly _containsEmbeddedLanguages: boolean; - private readonly _seenLanguages: boolean[]; - private readonly _initialState: StackElement; - private _maxTokenizationLineLength: number; - private _tokenizationWarningAlreadyShown: boolean; - - constructor(scopeRegistry: TMScopeRegistry, languageId: LanguageId, grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean, @INotificationService private readonly notificationService: INotificationService, @IConfigurationService readonly configurationService: IConfigurationService) { - this._scopeRegistry = scopeRegistry; - this._languageId = languageId; - this._grammar = grammar; - this._initialState = initialState; - this._containsEmbeddedLanguages = containsEmbeddedLanguages; - this._seenLanguages = []; - this._maxTokenizationLineLength = configurationService.getValue<number>('editor.maxTokenizationLineLength'); - } - - public getInitialState(): IState { - return this._initialState; - } - - public tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult { - throw new Error('Not supported!'); - } - - public tokenize2(line: string, state: StackElement, offsetDelta: number): TokenizationResult2 { - if (offsetDelta !== 0) { - throw new Error('Unexpected: offsetDelta should be 0.'); - } - - // Do not attempt to tokenize if a line is too long - if (line.length >= this._maxTokenizationLineLength) { - if (!this._tokenizationWarningAlreadyShown) { - this._tokenizationWarningAlreadyShown = true; - this.notificationService.warn(nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`.")); - } - console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); - return nullTokenize2(this._languageId, line, state, offsetDelta); - } - - let textMateResult = this._grammar.tokenizeLine2(line, state); - - if (this._containsEmbeddedLanguages) { - let seenLanguages = this._seenLanguages; - let tokens = textMateResult.tokens; - - // Must check if any of the embedded languages was hit - for (let i = 0, len = (tokens.length >>> 1); i < len; i++) { - let metadata = tokens[(i << 1) + 1]; - let languageId = TokenMetadata.getLanguageId(metadata); - - if (!seenLanguages[languageId]) { - seenLanguages[languageId] = true; - this._scopeRegistry.onEncounteredLanguage(languageId); - } - } - } - - let endState: StackElement; - // try to save an object if possible - if (state.equals(textMateResult.ruleStack)) { - endState = state; - } else { - endState = textMateResult.ruleStack; - - } - - return new TokenizationResult2(textMateResult.tokens, endState); - } -} diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts deleted file mode 100644 index b6bc58c24a..0000000000 --- a/src/vs/workbench/services/textMate/browser/textMateService.ts +++ /dev/null @@ -1,66 +0,0 @@ -/*--------------------------------------------------------------------------------------------- - * Copyright (c) Microsoft Corporation. All rights reserved. - * Licensed under the Source EULA. See License.txt in the project root for license information. - *--------------------------------------------------------------------------------------------*/ - -import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; -import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; -import * as vscodeTextmate from 'vscode-textmate'; -import * as onigasm from 'onigasm-umd'; -import { IModeService } from 'vs/editor/common/services/modeService'; -import { IFileService } from 'vs/platform/files/common/files'; -import { ILogService } from 'vs/platform/log/common/log'; -import { INotificationService } from 'vs/platform/notification/common/notification'; -import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; - -export class TextMateService extends AbstractTextMateService { - - constructor( - @IModeService modeService: IModeService, - @IWorkbenchThemeService themeService: IWorkbenchThemeService, - @IFileService fileService: IFileService, - @INotificationService notificationService: INotificationService, - @ILogService logService: ILogService, - @IConfigurationService configurationService: IConfigurationService - ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService); - } - - protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> { - return import('vscode-textmate'); - } - - protected _getRegistryOptions(parseRawGrammar: (content: string, filePath: string) => vscodeTextmate.IRawGrammar): vscodeTextmate.RegistryOptions { - const result = super._getRegistryOptions(parseRawGrammar); - result.getOnigLib = () => loadOnigasm(); - return result; - } -} - -let onigasmPromise: Promise<vscodeTextmate.IOnigLib> | null = null; -async function loadOnigasm(): Promise<vscodeTextmate.IOnigLib> { - if (!onigasmPromise) { - onigasmPromise = doLoadOnigasm(); - } - return onigasmPromise; -} - -async function doLoadOnigasm(): Promise<vscodeTextmate.IOnigLib> { - const wasmBytes = await loadOnigasmWASM(); - await onigasm.loadWASM(wasmBytes); - return { - createOnigScanner(patterns: string[]) { return new onigasm.OnigScanner(patterns); }, - createOnigString(s: string) { return new onigasm.OnigString(s); } - }; -} - -async function loadOnigasmWASM(): Promise<ArrayBuffer> { - const wasmPath = require.toUrl('onigasm-umd/../onigasm.wasm'); - const response = await fetch(wasmPath); - const bytes = await response.arrayBuffer(); - return bytes; -} - -registerSingleton(ITextMateService, TextMateService); diff --git a/src/vs/workbench/services/textMate/common/cgmanifest.json b/src/vs/workbench/services/textMate/electron-browser/cgmanifest.json similarity index 100% rename from src/vs/workbench/services/textMate/common/cgmanifest.json rename to src/vs/workbench/services/textMate/electron-browser/cgmanifest.json diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts index 5ac94859a8..0d8a3b7769 100644 --- a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts @@ -3,14 +3,512 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ +import * as nls from 'vs/nls'; +import * as dom from 'vs/base/browser/dom'; +import { Color } from 'vs/base/common/color'; +import { onUnexpectedError } from 'vs/base/common/errors'; +import { Emitter, Event } from 'vs/base/common/event'; +import * as resources from 'vs/base/common/resources'; +import * as types from 'vs/base/common/types'; +import { URI } from 'vs/base/common/uri'; +import { TokenizationResult, TokenizationResult2 } from 'vs/editor/common/core/token'; +import { IState, ITokenizationSupport, LanguageId, TokenMetadata, TokenizationRegistry } from 'vs/editor/common/modes'; +import { nullTokenize2 } from 'vs/editor/common/modes/nullMode'; +import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/tokenization'; +import { IModeService } from 'vs/editor/common/services/modeService'; +import { IFileService } from 'vs/platform/files/common/files'; +import { ILogService } from 'vs/platform/log/common/log'; +import { INotificationService } from 'vs/platform/notification/common/notification'; +import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; +import { IEmbeddedLanguagesMap, ITMSyntaxExtensionPoint, TokenTypesContribution, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; +import { ITokenColorizationRule, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; +import { IEmbeddedLanguagesMap as IEmbeddedLanguagesMap2, IGrammar, ITokenTypeMap, Registry, StackElement, StandardTokenType } from 'vscode-textmate'; +import { Disposable, IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { AbstractTextMateService } from 'vs/workbench/services/textMate/browser/abstractTextMateService'; -export class TextMateService extends AbstractTextMateService { +export class TMScopeRegistry { - protected _loadVSCodeTextmate(): Promise<typeof import('vscode-textmate')> { - return import('vscode-textmate'); + private _scopeNameToLanguageRegistration: { [scopeName: string]: TMLanguageRegistration; }; + private _encounteredLanguages: boolean[]; + + private readonly _onDidEncounterLanguage = new Emitter<LanguageId>(); + public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; + + constructor() { + this.reset(); + } + + public reset(): void { + this._scopeNameToLanguageRegistration = Object.create(null); + this._encounteredLanguages = []; + } + + public register(scopeName: string, grammarLocation: URI, embeddedLanguages?: IEmbeddedLanguagesMap, tokenTypes?: TokenTypesContribution): void { + if (this._scopeNameToLanguageRegistration[scopeName]) { + const existingRegistration = this._scopeNameToLanguageRegistration[scopeName]; + if (!resources.isEqual(existingRegistration.grammarLocation, grammarLocation)) { + console.warn( + `Overwriting grammar scope name to file mapping for scope ${scopeName}.\n` + + `Old grammar file: ${existingRegistration.grammarLocation.toString()}.\n` + + `New grammar file: ${grammarLocation.toString()}` + ); + } + } + this._scopeNameToLanguageRegistration[scopeName] = new TMLanguageRegistration(scopeName, grammarLocation, embeddedLanguages, tokenTypes); + } + + public getLanguageRegistration(scopeName: string): TMLanguageRegistration { + return this._scopeNameToLanguageRegistration[scopeName] || null; + } + + public getGrammarLocation(scopeName: string): URI | null { + let data = this.getLanguageRegistration(scopeName); + return data ? data.grammarLocation : null; + } + + /** + * To be called when tokenization found/hit an embedded language. + */ + public onEncounteredLanguage(languageId: LanguageId): void { + if (!this._encounteredLanguages[languageId]) { + this._encounteredLanguages[languageId] = true; + this._onDidEncounterLanguage.fire(languageId); + } + } +} + +export class TMLanguageRegistration { + _topLevelScopeNameDataBrand: void; + + readonly scopeName: string; + readonly grammarLocation: URI; + readonly embeddedLanguages: IEmbeddedLanguagesMap; + readonly tokenTypes: ITokenTypeMap; + + constructor(scopeName: string, grammarLocation: URI, embeddedLanguages: IEmbeddedLanguagesMap | undefined, tokenTypes: TokenTypesContribution | undefined) { + this.scopeName = scopeName; + this.grammarLocation = grammarLocation; + + // embeddedLanguages handling + this.embeddedLanguages = Object.create(null); + + if (embeddedLanguages) { + // If embeddedLanguages are configured, fill in `this._embeddedLanguages` + let scopes = Object.keys(embeddedLanguages); + for (let i = 0, len = scopes.length; i < len; i++) { + let scope = scopes[i]; + let language = embeddedLanguages[scope]; + if (typeof language !== 'string') { + // never hurts to be too careful + continue; + } + this.embeddedLanguages[scope] = language; + } + } + + this.tokenTypes = Object.create(null); + if (tokenTypes) { + // If tokenTypes is configured, fill in `this._tokenTypes` + const scopes = Object.keys(tokenTypes); + for (const scope of scopes) { + const tokenType = tokenTypes[scope]; + switch (tokenType) { + case 'string': + this.tokenTypes[scope] = StandardTokenType.String; + break; + case 'other': + this.tokenTypes[scope] = StandardTokenType.Other; + break; + case 'comment': + this.tokenTypes[scope] = StandardTokenType.Comment; + break; + } + } + } + } +} + +interface ICreateGrammarResult { + languageId: LanguageId; + grammar: IGrammar; + initialState: StackElement; + containsEmbeddedLanguages: boolean; +} + +export class TextMateService extends Disposable implements ITextMateService { + public _serviceBrand: any; + + private readonly _onDidEncounterLanguage: Emitter<LanguageId> = this._register(new Emitter<LanguageId>()); + public readonly onDidEncounterLanguage: Event<LanguageId> = this._onDidEncounterLanguage.event; + + private readonly _styleElement: HTMLStyleElement; + private readonly _createdModes: string[]; + + private _scopeRegistry: TMScopeRegistry; + private _injections: { [scopeName: string]: string[]; }; + private _injectedEmbeddedLanguages: { [scopeName: string]: IEmbeddedLanguagesMap[]; }; + private _languageToScope: Map<string, string>; + private _grammarRegistry: Promise<[Registry, StackElement]> | null; + private _tokenizersRegistrations: IDisposable[]; + private _currentTokenColors: ITokenColorizationRule[] | null; + private _themeListener: IDisposable | null; + + constructor( + @IModeService private readonly _modeService: IModeService, + @IWorkbenchThemeService private readonly _themeService: IWorkbenchThemeService, + @IFileService private readonly _fileService: IFileService, + @INotificationService private readonly _notificationService: INotificationService, + @ILogService private readonly _logService: ILogService, + @IConfigurationService private readonly _configurationService: IConfigurationService + ) { + super(); + this._styleElement = dom.createStyleSheet(); + this._styleElement.className = 'vscode-tokens-styles'; + this._createdModes = []; + this._scopeRegistry = new TMScopeRegistry(); + this._scopeRegistry.onDidEncounterLanguage((language) => this._onDidEncounterLanguage.fire(language)); + this._injections = {}; + this._injectedEmbeddedLanguages = {}; + this._languageToScope = new Map<string, string>(); + this._grammarRegistry = null; + this._tokenizersRegistrations = []; + this._currentTokenColors = null; + this._themeListener = null; + + grammarsExtPoint.setHandler((extensions) => { + this._scopeRegistry.reset(); + this._injections = {}; + this._injectedEmbeddedLanguages = {}; + this._languageToScope = new Map<string, string>(); + this._grammarRegistry = null; + this._tokenizersRegistrations = dispose(this._tokenizersRegistrations); + this._currentTokenColors = null; + if (this._themeListener) { + this._themeListener.dispose(); + this._themeListener = null; + } + + for (const extension of extensions) { + let grammars = extension.value; + for (const grammar of grammars) { + this._handleGrammarExtensionPointUser(extension.description.extensionLocation, grammar, extension.collector); + } + } + + for (const createMode of this._createdModes) { + this._registerDefinitionIfAvailable(createMode); + } + }); + + // Generate some color map until the grammar registry is loaded + let colorTheme = this._themeService.getColorTheme(); + let defaultForeground: Color = Color.transparent; + let defaultBackground: Color = Color.transparent; + for (let i = 0, len = colorTheme.tokenColors.length; i < len; i++) { + let rule = colorTheme.tokenColors[i]; + if (!rule.scope && rule.settings) { + if (rule.settings.foreground) { + defaultForeground = Color.fromHex(rule.settings.foreground); + } + if (rule.settings.background) { + defaultBackground = Color.fromHex(rule.settings.background); + } + } + } + TokenizationRegistry.setColorMap([null!, defaultForeground, defaultBackground]); + + this._modeService.onDidCreateMode((mode) => { + let modeId = mode.getId(); + this._createdModes.push(modeId); + this._registerDefinitionIfAvailable(modeId); + }); + } + + private _registerDefinitionIfAvailable(modeId: string): void { + if (this._languageToScope.has(modeId)) { + const promise = this._createGrammar(modeId).then((r) => { + return new TMTokenization(this._scopeRegistry, r.languageId, r.grammar, r.initialState, r.containsEmbeddedLanguages, this._notificationService, this._configurationService); + }, e => { + onUnexpectedError(e); + return null; + }); + this._tokenizersRegistrations.push(TokenizationRegistry.registerPromise(modeId, promise)); + } + } + + private async _createGrammarRegistry(): Promise<[Registry, StackElement]> { + const { Registry, INITIAL, parseRawGrammar } = await import('vscode-textmate'); + const grammarRegistry = new Registry({ + loadGrammar: async (scopeName: string) => { + const location = this._scopeRegistry.getGrammarLocation(scopeName); + if (!location) { + this._logService.trace(`No grammar found for scope ${scopeName}`); + return null; + } + try { + const content = await this._fileService.readFile(location); + return parseRawGrammar(content.value.toString(), location.path); + } catch (e) { + this._logService.error(`Unable to load and parse grammar for scope ${scopeName} from ${location}`, e); + return null; + } + }, + getInjections: (scopeName: string) => { + const scopeParts = scopeName.split('.'); + let injections: string[] = []; + for (let i = 1; i <= scopeParts.length; i++) { + const subScopeName = scopeParts.slice(0, i).join('.'); + injections = [...injections, ...(this._injections[subScopeName] || [])]; + } + return injections; + } + }); + this._updateTheme(grammarRegistry); + this._themeListener = this._themeService.onDidColorThemeChange((e) => this._updateTheme(grammarRegistry)); + return <[Registry, StackElement]>[grammarRegistry, INITIAL]; + } + + private _getOrCreateGrammarRegistry(): Promise<[Registry, StackElement]> { + if (!this._grammarRegistry) { + this._grammarRegistry = this._createGrammarRegistry(); + } + return this._grammarRegistry; + } + + private static _toColorMap(colorMap: string[]): Color[] { + let result: Color[] = [null!]; + for (let i = 1, len = colorMap.length; i < len; i++) { + result[i] = Color.fromHex(colorMap[i]); + } + return result; + } + + private _updateTheme(grammarRegistry: Registry): void { + let colorTheme = this._themeService.getColorTheme(); + if (!this.compareTokenRules(colorTheme.tokenColors)) { + return; + } + grammarRegistry.setTheme({ name: colorTheme.label, settings: colorTheme.tokenColors }); + let colorMap = TextMateService._toColorMap(grammarRegistry.getColorMap()); + let cssRules = generateTokensCSSForColorMap(colorMap); + this._styleElement.innerHTML = cssRules; + TokenizationRegistry.setColorMap(colorMap); + } + + private compareTokenRules(newRules: ITokenColorizationRule[]): boolean { + let currRules = this._currentTokenColors; + this._currentTokenColors = newRules; + if (!newRules || !currRules || newRules.length !== currRules.length) { + return true; + } + for (let i = newRules.length - 1; i >= 0; i--) { + let r1 = newRules[i]; + let r2 = currRules[i]; + if (r1.scope !== r2.scope) { + return true; + } + let s1 = r1.settings; + let s2 = r2.settings; + if (s1 && s2) { + if (s1.fontStyle !== s2.fontStyle || s1.foreground !== s2.foreground || s1.background !== s2.background) { + return true; + } + } else if (!s1 || !s2) { + return true; + } + } + return false; + } + + private _handleGrammarExtensionPointUser(extensionLocation: URI, syntax: ITMSyntaxExtensionPoint, collector: ExtensionMessageCollector): void { + if (syntax.language && ((typeof syntax.language !== 'string') || !this._modeService.isRegisteredMode(syntax.language))) { + collector.error(nls.localize('invalid.language', "Unknown language in `contributes.{0}.language`. Provided value: {1}", grammarsExtPoint.name, String(syntax.language))); + return; + } + if (!syntax.scopeName || (typeof syntax.scopeName !== 'string')) { + collector.error(nls.localize('invalid.scopeName', "Expected string in `contributes.{0}.scopeName`. Provided value: {1}", grammarsExtPoint.name, String(syntax.scopeName))); + return; + } + if (!syntax.path || (typeof syntax.path !== 'string')) { + collector.error(nls.localize('invalid.path.0', "Expected string in `contributes.{0}.path`. Provided value: {1}", grammarsExtPoint.name, String(syntax.path))); + return; + } + if (syntax.injectTo && (!Array.isArray(syntax.injectTo) || syntax.injectTo.some(scope => typeof scope !== 'string'))) { + collector.error(nls.localize('invalid.injectTo', "Invalid value in `contributes.{0}.injectTo`. Must be an array of language scope names. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.injectTo))); + return; + } + if (syntax.embeddedLanguages && !types.isObject(syntax.embeddedLanguages)) { + collector.error(nls.localize('invalid.embeddedLanguages', "Invalid value in `contributes.{0}.embeddedLanguages`. Must be an object map from scope name to language. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.embeddedLanguages))); + return; + } + + if (syntax.tokenTypes && !types.isObject(syntax.tokenTypes)) { + collector.error(nls.localize('invalid.tokenTypes', "Invalid value in `contributes.{0}.tokenTypes`. Must be an object map from scope name to token type. Provided value: {1}", grammarsExtPoint.name, JSON.stringify(syntax.tokenTypes))); + return; + } + + const grammarLocation = resources.joinPath(extensionLocation, syntax.path); + if (!resources.isEqualOrParent(grammarLocation, extensionLocation)) { + collector.warn(nls.localize('invalid.path.1', "Expected `contributes.{0}.path` ({1}) to be included inside extension's folder ({2}). This might make the extension non-portable.", grammarsExtPoint.name, grammarLocation.path, extensionLocation.path)); + } + + this._scopeRegistry.register(syntax.scopeName, grammarLocation, syntax.embeddedLanguages, syntax.tokenTypes); + + if (syntax.injectTo) { + for (let injectScope of syntax.injectTo) { + let injections = this._injections[injectScope]; + if (!injections) { + this._injections[injectScope] = injections = []; + } + injections.push(syntax.scopeName); + } + + if (syntax.embeddedLanguages) { + for (let injectScope of syntax.injectTo) { + let injectedEmbeddedLanguages = this._injectedEmbeddedLanguages[injectScope]; + if (!injectedEmbeddedLanguages) { + this._injectedEmbeddedLanguages[injectScope] = injectedEmbeddedLanguages = []; + } + injectedEmbeddedLanguages.push(syntax.embeddedLanguages); + } + } + } + + let modeId = syntax.language; + if (modeId) { + this._languageToScope.set(modeId, syntax.scopeName); + } + } + + private _resolveEmbeddedLanguages(embeddedLanguages: IEmbeddedLanguagesMap): IEmbeddedLanguagesMap2 { + let scopes = Object.keys(embeddedLanguages); + let result: IEmbeddedLanguagesMap2 = Object.create(null); + for (let i = 0, len = scopes.length; i < len; i++) { + let scope = scopes[i]; + let language = embeddedLanguages[scope]; + let languageIdentifier = this._modeService.getLanguageIdentifier(language); + if (languageIdentifier) { + result[scope] = languageIdentifier.id; + } + } + return result; + } + + public async createGrammar(modeId: string): Promise<IGrammar> { + const { grammar } = await this._createGrammar(modeId); + return grammar; + } + + private async _createGrammar(modeId: string): Promise<ICreateGrammarResult> { + const scopeName = this._languageToScope.get(modeId); + if (typeof scopeName !== 'string') { + // No TM grammar defined + return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); + } + const languageRegistration = this._scopeRegistry.getLanguageRegistration(scopeName); + if (!languageRegistration) { + // No TM grammar defined + return Promise.reject(new Error(nls.localize('no-tm-grammar', "No TM Grammar registered for this language."))); + } + let embeddedLanguages = this._resolveEmbeddedLanguages(languageRegistration.embeddedLanguages); + let rawInjectedEmbeddedLanguages = this._injectedEmbeddedLanguages[scopeName]; + if (rawInjectedEmbeddedLanguages) { + let injectedEmbeddedLanguages: IEmbeddedLanguagesMap2[] = rawInjectedEmbeddedLanguages.map(this._resolveEmbeddedLanguages.bind(this)); + for (const injected of injectedEmbeddedLanguages) { + for (const scope of Object.keys(injected)) { + embeddedLanguages[scope] = injected[scope]; + } + } + } + + let languageId = this._modeService.getLanguageIdentifier(modeId)!.id; + let containsEmbeddedLanguages = (Object.keys(embeddedLanguages).length > 0); + + const [grammarRegistry, initialState] = await this._getOrCreateGrammarRegistry(); + const grammar = await grammarRegistry.loadGrammarWithConfiguration(scopeName, languageId, { embeddedLanguages, tokenTypes: languageRegistration.tokenTypes }); + return { + languageId: languageId, + grammar: grammar, + initialState: initialState, + containsEmbeddedLanguages: containsEmbeddedLanguages + }; + } +} + +class TMTokenization implements ITokenizationSupport { + + private readonly _scopeRegistry: TMScopeRegistry; + private readonly _languageId: LanguageId; + private readonly _grammar: IGrammar; + private readonly _containsEmbeddedLanguages: boolean; + private readonly _seenLanguages: boolean[]; + private readonly _initialState: StackElement; + private _maxTokenizationLineLength: number; + private _tokenizationWarningAlreadyShown: boolean; + + constructor(scopeRegistry: TMScopeRegistry, languageId: LanguageId, grammar: IGrammar, initialState: StackElement, containsEmbeddedLanguages: boolean, @INotificationService private readonly notificationService: INotificationService, @IConfigurationService readonly configurationService: IConfigurationService) { + this._scopeRegistry = scopeRegistry; + this._languageId = languageId; + this._grammar = grammar; + this._initialState = initialState; + this._containsEmbeddedLanguages = containsEmbeddedLanguages; + this._seenLanguages = []; + this._maxTokenizationLineLength = configurationService.getValue<number>('editor.maxTokenizationLineLength'); + } + + public getInitialState(): IState { + return this._initialState; + } + + public tokenize(line: string, state: IState, offsetDelta: number): TokenizationResult { + throw new Error('Not supported!'); + } + + public tokenize2(line: string, state: StackElement, offsetDelta: number): TokenizationResult2 { + if (offsetDelta !== 0) { + throw new Error('Unexpected: offsetDelta should be 0.'); + } + + // Do not attempt to tokenize if a line is too long + if (line.length >= this._maxTokenizationLineLength) { + if (!this._tokenizationWarningAlreadyShown) { + this._tokenizationWarningAlreadyShown = true; + this.notificationService.warn(nls.localize('too many characters', "Tokenization is skipped for long lines for performance reasons. The length of a long line can be configured via `editor.maxTokenizationLineLength`.")); + } + console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); + return nullTokenize2(this._languageId, line, state, offsetDelta); + } + + let textMateResult = this._grammar.tokenizeLine2(line, state); + + if (this._containsEmbeddedLanguages) { + let seenLanguages = this._seenLanguages; + let tokens = textMateResult.tokens; + + // Must check if any of the embedded languages was hit + for (let i = 0, len = (tokens.length >>> 1); i < len; i++) { + let metadata = tokens[(i << 1) + 1]; + let languageId = TokenMetadata.getLanguageId(metadata); + + if (!seenLanguages[languageId]) { + seenLanguages[languageId] = true; + this._scopeRegistry.onEncounteredLanguage(languageId); + } + } + } + + let endState: StackElement; + // try to save an object if possible + if (state.equals(textMateResult.ruleStack)) { + endState = state; + } else { + endState = textMateResult.ruleStack; + + } + + return new TokenizationResult2(textMateResult.tokens, endState); } } diff --git a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts index 09d81533fa..8a07bf7270 100644 --- a/src/vs/workbench/services/textfile/common/textFileEditorModel.ts +++ b/src/vs/workbench/services/textfile/common/textFileEditorModel.ts @@ -144,7 +144,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } } - private async onFileChanges(e: FileChangesEvent): Promise<void> { + private onFileChanges(e: FileChangesEvent): void { let fileEventImpactsModel = false; let newInOrphanModeGuess: boolean | undefined; @@ -167,25 +167,28 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } if (fileEventImpactsModel && this.inOrphanMode !== newInOrphanModeGuess) { - let newInOrphanModeValidated: boolean = false; + let checkOrphanedPromise: Promise<boolean>; if (newInOrphanModeGuess) { // We have received reports of users seeing delete events even though the file still // exists (network shares issue: https://github.com/Microsoft/vscode/issues/13665). // Since we do not want to mark the model as orphaned, we have to check if the // file is really gone and not just a faulty file event. - await timeout(100); + checkOrphanedPromise = timeout(100).then(() => { + if (this.disposed) { + return true; + } - if (this.disposed) { - newInOrphanModeValidated = true; - } else { - const exists = await this.fileService.exists(this.resource); - newInOrphanModeValidated = !exists; + return this.fileService.exists(this.resource).then(exists => !exists); + }); + } else { + checkOrphanedPromise = Promise.resolve(false); + } + + checkOrphanedPromise.then(newInOrphanModeValidated => { + if (this.inOrphanMode !== newInOrphanModeValidated && !this.disposed) { + this.setOrphaned(newInOrphanModeValidated); } - } - - if (this.inOrphanMode !== newInOrphanModeValidated && !this.disposed) { - this.setOrphaned(newInOrphanModeValidated); - } + }); } } @@ -236,11 +239,13 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil return this.backupFileService.backupResource<IBackupMetaData>(target, this.createSnapshot(), this.versionId, meta); } + + return Promise.resolve(); } async revert(soft?: boolean): Promise<void> { if (!this.isResolved()) { - return; + return Promise.resolve(undefined); } // Cancel any running auto-save @@ -249,21 +254,25 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // Unset flags const undo = this.setDirty(false); - // Force read from disk unless reverting soft - if (!soft) { - try { - await this.load({ forceReadFromDisk: true }); - } catch (error) { - - // Set flags back to previous values, we are still dirty if revert failed - undo(); - - throw error; - } + let loadPromise: Promise<unknown>; + if (soft) { + loadPromise = Promise.resolve(); + } else { + loadPromise = this.load({ forceReadFromDisk: true }); } - // Emit file change event - this._onDidStateChange.fire(StateChange.REVERTED); + try { + await loadPromise; + + // Emit file change event + this._onDidStateChange.fire(StateChange.REVERTED); + } catch (error) { + + // Set flags back to previous values, we are still dirty if revert failed + undo(); + + return Promise.reject(error); + } } async load(options?: ILoadOptions): Promise<ITextFileEditorModel> { @@ -591,7 +600,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil save(options: ISaveOptions = Object.create(null)): Promise<void> { if (!this.isResolved()) { - return Promise.resolve(); + return Promise.resolve(undefined); } this.logService.trace('save() - enter', this.resource); @@ -617,7 +626,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if (this.saveSequentializer.hasPendingSave(versionId)) { this.logService.trace(`doSave(${versionId}) - exit - found a pending save for versionId ${versionId}`, this.resource); - return this.saveSequentializer.pendingSave || Promise.resolve(); + return this.saveSequentializer.pendingSave || Promise.resolve(undefined); } // Return early if not dirty (unless forced) or version changed meanwhile @@ -630,7 +639,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil if ((!options.force && !this.dirty) || versionId !== this.versionId) { this.logService.trace(`doSave(${versionId}) - exit - because not dirty and/or versionId is different (this.isDirty: ${this.dirty}, this.versionId: ${this.versionId})`, this.resource); - return Promise.resolve(); + return Promise.resolve(undefined); } // Return if currently saving by storing this save request as the next save that should happen. @@ -783,7 +792,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil } // Check for global settings file - if (isEqual(this.resource, this.environmentService.settingsResource, !isLinux)) { + if (isEqual(this.resource, URI.file(this.environmentService.appSettingsPath), !isLinux)) { return 'global-settings'; } diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index f26eadc667..f36e3b0221 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -443,7 +443,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer return this.fileService.del(resource, options); } - async move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata> { + async move(source: URI, target: URI, overwrite?: boolean): Promise<void> { const waitForPromises: Promise<unknown>[] = []; // Event @@ -498,12 +498,10 @@ export abstract class TextFileService extends Disposable implements ITextFileSer // Rename to target try { - const stat = await this.fileService.move(source, target, overwrite); + await this.fileService.move(source, target, overwrite); // Load models that were dirty before await Promise.all(dirtyTargetModelUris.map(dirtyTargetModel => this.models.loadOrCreate(dirtyTargetModel))); - - return stat; } catch (error) { // In case of an error, discard any dirty target backups that were made diff --git a/src/vs/workbench/services/textfile/common/textfiles.ts b/src/vs/workbench/services/textfile/common/textfiles.ts index c3027baedf..8c46a858ac 100644 --- a/src/vs/workbench/services/textfile/common/textfiles.ts +++ b/src/vs/workbench/services/textfile/common/textfiles.ts @@ -125,7 +125,7 @@ export interface ITextFileService extends IDisposable { /** * Move a file. If the file is dirty, its contents will be preserved and restored. */ - move(source: URI, target: URI, overwrite?: boolean): Promise<IFileStatWithMetadata>; + move(source: URI, target: URI, overwrite?: boolean): Promise<void>; /** * Brings up the confirm dialog to either save, don't save or cancel. diff --git a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts index a9372a7605..8c5fc900d9 100644 --- a/src/vs/workbench/services/textfile/test/textFileService.io.test.ts +++ b/src/vs/workbench/services/textfile/test/textFileService.io.test.ts @@ -17,7 +17,7 @@ import { ModelServiceImpl } from 'vs/editor/common/services/modelServiceImpl'; import { Schemas } from 'vs/base/common/network'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { rimraf, RimRafMode, copy, readFile, exists } from 'vs/base/node/pfs'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose, IDisposable } from 'vs/base/common/lifecycle'; import { FileService } from 'vs/workbench/services/files/common/fileService'; import { NullLogService } from 'vs/platform/log/common/log'; import { getRandomTestPath } from 'vs/base/test/node/testUtils'; @@ -76,7 +76,7 @@ suite('Files - TextFileService i/o', () => { const parentDir = getRandomTestPath(tmpdir(), 'vsctests', 'textfileservice'); let accessor: ServiceAccessor; - const disposables = new DisposableStore(); + let disposables: IDisposable[] = []; let service: ITextFileService; let testDir: string; @@ -88,8 +88,8 @@ suite('Files - TextFileService i/o', () => { const fileService = new FileService(logService); const fileProvider = new DiskFileSystemProvider(logService); - disposables.add(fileService.registerProvider(Schemas.file, fileProvider)); - disposables.add(fileProvider); + disposables.push(fileService.registerProvider(Schemas.file, fileProvider)); + disposables.push(fileProvider); const collection = new ServiceCollection(); collection.set(IFileService, fileService); @@ -108,7 +108,7 @@ suite('Files - TextFileService i/o', () => { (<TextFileEditorModelManager>accessor.textFileService.models).dispose(); accessor.untitledEditorService.revertAll(); - disposables.clear(); + disposables = dispose(disposables); await rimraf(parentDir, RimRafMode.MOVE); }); diff --git a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts index 987f060544..340bb88cf9 100644 --- a/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts +++ b/src/vs/workbench/services/textmodelResolver/common/textModelResolverService.ts @@ -151,10 +151,10 @@ export class TextModelResolverService implements ITextModelService { const cachedModel = this.modelService.getModel(resource); if (!cachedModel) { - throw new Error('Cant resolve inmemory resource'); + return Promise.reject(new Error('Cant resolve inmemory resource')); } - return new ImmortalReference(this.instantiationService.createInstance(ResourceEditorModel, resource) as IResolvedTextEditorModel); + return Promise.resolve(new ImmortalReference(this.instantiationService.createInstance(ResourceEditorModel, resource) as IResolvedTextEditorModel)); } const ref = this.resourceModelCollection.acquire(resource.toString()); diff --git a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts index ef50604c8d..efda47b66a 100644 --- a/src/vs/workbench/services/themes/browser/workbenchThemeService.ts +++ b/src/vs/workbench/services/themes/browser/workbenchThemeService.ts @@ -45,7 +45,6 @@ const defaultThemeExtensionId = 'sql-theme-carbon'; const oldDefaultThemeExtensionId = 'vscode-theme-colorful-defaults'; const DEFAULT_ICON_THEME_SETTING_VALUE = 'vs-seti'; -const DEFAULT_ICON_THEME_ID = 'vscode.vscode-theme-seti-vs-seti'; const fileIconsEnabledClass = 'file-icons-enabled'; const colorThemeRulesClassName = 'contributedColorTheme'; @@ -193,10 +192,10 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (!theme) { // current theme is no longer available prevFileIconId = this.currentIconTheme.id; - this.setFileIconTheme(DEFAULT_ICON_THEME_ID, 'auto'); + this.setFileIconTheme(DEFAULT_ICON_THEME_SETTING_VALUE, 'auto'); } else { // restore color - if (this.currentIconTheme.id === DEFAULT_ICON_THEME_ID && !types.isUndefined(prevFileIconId) && await this.iconThemeStore.findThemeData(prevFileIconId)) { + if (this.currentIconTheme.id === DEFAULT_ICON_THEME_SETTING_VALUE && !types.isUndefined(prevFileIconId) && await this.iconThemeStore.findThemeData(prevFileIconId)) { this.setFileIconTheme(prevFileIconId, 'auto'); prevFileIconId = undefined; } @@ -272,7 +271,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { if (devThemes.length) { return this.setFileIconTheme(devThemes[0].id, ConfigurationTarget.MEMORY); } else { - return this.setFileIconTheme(theme ? theme.id : DEFAULT_ICON_THEME_ID, undefined); + return this.setFileIconTheme(theme && theme.id || DEFAULT_ICON_THEME_SETTING_VALUE, undefined); } }); }), @@ -295,7 +294,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { let iconThemeSetting = this.configurationService.getValue<string | null>(ICON_THEME_SETTING); if (iconThemeSetting !== this.currentIconTheme.settingsId) { this.iconThemeStore.findThemeBySettingsId(iconThemeSetting).then(theme => { - this.setFileIconTheme(theme ? theme.id : DEFAULT_ICON_THEME_ID, undefined); + this.setFileIconTheme(theme && theme.id || DEFAULT_ICON_THEME_SETTING_VALUE, undefined); }); } } @@ -482,7 +481,7 @@ export class WorkbenchThemeService implements IWorkbenchThemeService { this.doSetFileIconTheme(newIconTheme); // remember theme data for a quick restore - if (newIconTheme.isLoaded && (!newIconTheme.location || !getRemoteAuthority(newIconTheme.location))) { + if (newIconTheme.isLoaded && newIconTheme.location && !getRemoteAuthority(newIconTheme.location)) { this.storageService.store(PERSISTED_ICON_THEME_STORAGE_KEY, newIconTheme.toStorageData(), StorageScope.GLOBAL); } diff --git a/src/vs/workbench/services/themes/common/colorThemeData.ts b/src/vs/workbench/services/themes/common/colorThemeData.ts index a6f3188bf0..ad6b3a828a 100644 --- a/src/vs/workbench/services/themes/common/colorThemeData.ts +++ b/src/vs/workbench/services/themes/common/colorThemeData.ts @@ -251,7 +251,7 @@ export class ColorThemeData implements IColorTheme { break; case 'themeTokenColors': case 'id': case 'label': case 'settingsId': case 'extensionData': case 'watch': - (theme as any)[key] = data[key]; + theme[key] = data[key]; break; } } diff --git a/src/vs/workbench/services/themes/common/fileIconThemeData.ts b/src/vs/workbench/services/themes/common/fileIconThemeData.ts index d4a691c8c3..6472b581a7 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeData.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeData.ts @@ -118,7 +118,7 @@ export class FileIconThemeData implements IFileIconTheme { case 'hidesExplorerArrows': case 'hasFolderIcons': case 'watch': - (theme as any)[key] = data[key]; + theme[key] = data[key]; break; case 'location': theme.location = URI.revive(data.location); diff --git a/src/vs/workbench/services/themes/common/fileIconThemeStore.ts b/src/vs/workbench/services/themes/common/fileIconThemeStore.ts index 800f017ec8..0816834bbc 100644 --- a/src/vs/workbench/services/themes/common/fileIconThemeStore.ts +++ b/src/vs/workbench/services/themes/common/fileIconThemeStore.ts @@ -13,7 +13,6 @@ import { IExtensionService } from 'vs/workbench/services/extensions/common/exten import { Event, Emitter } from 'vs/base/common/event'; import { FileIconThemeData } from 'vs/workbench/services/themes/common/fileIconThemeData'; import { URI } from 'vs/base/common/uri'; -import { Disposable } from 'vs/base/common/lifecycle'; const iconThemeExtPoint = ExtensionsRegistry.registerExtensionPoint<IThemeExtensionPoint[]>({ extensionPoint: 'iconThemes', @@ -47,16 +46,16 @@ export interface FileIconThemeChangeEvent { added: FileIconThemeData[]; } -export class FileIconThemeStore extends Disposable { +export class FileIconThemeStore { private knownIconThemes: FileIconThemeData[]; + private readonly onDidChangeEmitter: Emitter<FileIconThemeChangeEvent>; - private readonly onDidChangeEmitter = this._register(new Emitter<FileIconThemeChangeEvent>()); - readonly onDidChange: Event<FileIconThemeChangeEvent> = this.onDidChangeEmitter.event; + public get onDidChange(): Event<FileIconThemeChangeEvent> { return this.onDidChangeEmitter.event; } constructor(@IExtensionService private readonly extensionService: IExtensionService) { - super(); this.knownIconThemes = []; + this.onDidChangeEmitter = new Emitter<FileIconThemeChangeEvent>(); this.initialize(); } @@ -168,4 +167,5 @@ export class FileIconThemeStore extends Disposable { return this.knownIconThemes; }); } + } diff --git a/src/vs/workbench/services/timer/electron-browser/timerService.ts b/src/vs/workbench/services/timer/electron-browser/timerService.ts index 1f2dbf365d..fd947df735 100644 --- a/src/vs/workbench/services/timer/electron-browser/timerService.ts +++ b/src/vs/workbench/services/timer/electron-browser/timerService.ts @@ -12,6 +12,7 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { isNonEmptyArray } from 'vs/base/common/arrays'; import { IUpdateService } from 'vs/platform/update/common/update'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; @@ -22,12 +23,14 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessi /* __GDPR__FRAGMENT__ "IMemoryInfo" : { "workingSetSize" : { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, + "peakWorkingSetSize": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "privateBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true }, "sharedBytes": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth", "isMeasurement": true } } */ export interface IMemoryInfo { readonly workingSetSize: number; + readonly peakWorkingSetSize: number; readonly privateBytes: number; readonly sharedBytes: number; } @@ -208,7 +211,7 @@ export interface IStartupMetrics { readonly ellapsedWorkspaceServiceInit: number; /** - * The time it took to load the main-bundle of the workbench, e.g. `workbench.main.js`. + * The time it took to load the main-bundle of the workbench, e.g `workbench.main.js`. * * * Happens in the renderer-process * * Measured with the `willLoadWorkbenchMain` and `didLoadWorkbenchMain` performance marks. @@ -352,13 +355,7 @@ class TimerService implements ITimerService { release = os.release(); arch = os.arch(); loadavg = os.loadavg(); - - const processMemoryInfo = await process.getProcessMemoryInfo(); - meminfo = { - workingSetSize: processMemoryInfo.residentSet, - privateBytes: processMemoryInfo.private, - sharedBytes: processMemoryInfo.shared - }; + meminfo = process.getProcessMemoryInfo(); isVMLikelyhood = Math.round((virtualMachineHint.value() * 100)); @@ -431,19 +428,16 @@ export function didUseCachedData(): boolean { if (!Boolean((<any>global).require.getConfig().nodeCachedData)) { return false; } - // There are loader events that signal if cached data was missing, rejected, - // or used. The former two mean no cached data. - let cachedDataFound = 0; - for (const event of require.getStats()) { - switch (event.type) { - case LoaderEventType.CachedDataRejected: - return false; - case LoaderEventType.CachedDataFound: - cachedDataFound += 1; - break; - } + // whenever cached data is produced or rejected a onNodeCachedData-callback is invoked. That callback + // stores data in the `MonacoEnvironment.onNodeCachedData` global. See: + // https://github.com/Microsoft/vscode/blob/efe424dfe76a492eab032343e2fa4cfe639939f0/src/vs/workbench/electron-browser/bootstrap/index.js#L299 + if (isNonEmptyArray(MonacoEnvironment.onNodeCachedData)) { + return false; } - return cachedDataFound > 0; + return true; } +declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }]; +declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] }; + //#endregion diff --git a/src/vs/workbench/services/viewlet/browser/viewlet.ts b/src/vs/workbench/services/viewlet/browser/viewlet.ts index a82651c768..39624a7d04 100644 --- a/src/vs/workbench/services/viewlet/browser/viewlet.ts +++ b/src/vs/workbench/services/viewlet/browser/viewlet.ts @@ -7,7 +7,7 @@ import { IViewlet } from 'vs/workbench/common/viewlet'; import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; import { ViewletDescriptor } from 'vs/workbench/browser/viewlet'; -import { ILocalProgressService } from 'vs/platform/progress/common/progress'; +import { IProgressService } from 'vs/platform/progress/common/progress'; export const IViewletService = createDecorator<IViewletService>('viewletService'); @@ -47,7 +47,7 @@ export interface IViewletService { /** * Returns the progress indicator for the side bar. */ - getProgressIndicator(id: string): ILocalProgressService | null; + getProgressIndicator(id: string): IProgressService | null; /** * Hide the active viewlet. diff --git a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts index 09347c163c..5d1f94806c 100644 --- a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts @@ -67,81 +67,74 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { } - private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise<boolean> { + private saveUntitedBeforeShutdown(reason: ShutdownReason): Promise<boolean> | undefined { if (reason !== ShutdownReason.LOAD && reason !== ShutdownReason.CLOSE) { - return false; // only interested when window is closing or loading + return undefined; // only interested when window is closing or loading } const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); if (!workspaceIdentifier || !isEqualOrParent(workspaceIdentifier.configPath, this.environmentService.untitledWorkspacesHome)) { - return false; // only care about untitled workspaces to ask for saving + return undefined; // only care about untitled workspaces to ask for saving } - const windowCount = await this.windowsService.getWindowCount(); - - if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { - return false; // Windows/Linux: quits when last window is closed, so do not ask then - } - - enum ConfirmResult { - SAVE, - DONT_SAVE, - CANCEL - } - - const save = { label: mnemonicButtonLabel(nls.localize('save', "Save")), result: ConfirmResult.SAVE }; - const dontSave = { label: mnemonicButtonLabel(nls.localize('doNotSave', "Don't Save")), result: ConfirmResult.DONT_SAVE }; - const cancel = { label: nls.localize('cancel', "Cancel"), result: ConfirmResult.CANCEL }; - - const buttons: { label: string; result: ConfirmResult; }[] = []; - if (isWindows) { - buttons.push(save, dontSave, cancel); - } else if (isLinux) { - buttons.push(dontSave, cancel, save); - } else { - buttons.push(save, cancel, dontSave); - } - - const message = nls.localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"); - const detail = nls.localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."); - const cancelId = buttons.indexOf(cancel); - - const res = await this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }); - - switch (buttons[res].result) { - - // Cancel: veto unload - case ConfirmResult.CANCEL: - return true; - - // Don't Save: delete workspace - case ConfirmResult.DONT_SAVE: - this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); - return false; - - // Save: save workspace, but do not veto unload if path provided - case ConfirmResult.SAVE: { - const newWorkspacePath = await this.pickNewWorkspacePath(); - if (!newWorkspacePath) { - return true; // keep veto if no target was provided - } - - try { - await this.saveWorkspaceAs(workspaceIdentifier, newWorkspacePath); - - const newWorkspaceIdentifier = await this.workspaceService.getWorkspaceIdentifier(newWorkspacePath); - - const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); - this.windowsService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); - - this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); - } catch (error) { - // ignore - } - - return false; + return this.windowsService.getWindowCount().then(windowCount => { + if (reason === ShutdownReason.CLOSE && !isMacintosh && windowCount === 1) { + return false; // Windows/Linux: quits when last window is closed, so do not ask then } - } + enum ConfirmResult { + SAVE, + DONT_SAVE, + CANCEL + } + + const save = { label: mnemonicButtonLabel(nls.localize('save', "Save")), result: ConfirmResult.SAVE }; + const dontSave = { label: mnemonicButtonLabel(nls.localize('doNotSave', "Don't Save")), result: ConfirmResult.DONT_SAVE }; + const cancel = { label: nls.localize('cancel', "Cancel"), result: ConfirmResult.CANCEL }; + + const buttons: { label: string; result: ConfirmResult; }[] = []; + if (isWindows) { + buttons.push(save, dontSave, cancel); + } else if (isLinux) { + buttons.push(dontSave, cancel, save); + } else { + buttons.push(save, cancel, dontSave); + } + + const message = nls.localize('saveWorkspaceMessage', "Do you want to save your workspace configuration as a file?"); + const detail = nls.localize('saveWorkspaceDetail', "Save your workspace if you plan to open it again."); + const cancelId = buttons.indexOf(cancel); + + return this.dialogService.show(Severity.Warning, message, buttons.map(button => button.label), { detail, cancelId }).then(res => { + switch (buttons[res].result) { + + // Cancel: veto unload + case ConfirmResult.CANCEL: + return true; + + // Don't Save: delete workspace + case ConfirmResult.DONT_SAVE: + this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); + return false; + + // Save: save workspace, but do not veto unload + case ConfirmResult.SAVE: { + return this.pickNewWorkspacePath().then(newWorkspacePath => { + if (newWorkspacePath) { + return this.saveWorkspaceAs(workspaceIdentifier, newWorkspacePath).then(_ => { + return this.workspaceService.getWorkspaceIdentifier(newWorkspacePath).then(newWorkspaceIdentifier => { + const label = this.labelService.getWorkspaceLabel(newWorkspaceIdentifier, { verbose: true }); + this.windowsService.addRecentlyOpened([{ label, workspace: newWorkspaceIdentifier }]); + this.workspaceService.deleteUntitledWorkspace(workspaceIdentifier); + return false; + }); + }, () => false); + } + return true; // keep veto if no target was provided + }); + } + } + }); + }); } pickNewWorkspacePath(): Promise<URI | undefined> { @@ -225,7 +218,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { newWorkspaceFolders = distinct(newWorkspaceFolders, folder => getComparisonKey(folder.uri)); if (state === WorkbenchState.EMPTY && newWorkspaceFolders.length === 0 || state === WorkbenchState.FOLDER && newWorkspaceFolders.length === 1) { - return; // return if the operation is a no-op for the current state + return Promise.resolve(); // return if the operation is a no-op for the current state } return this.createAndEnterWorkspace(newWorkspaceFolders); @@ -274,7 +267,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async createAndEnterWorkspace(folders: IWorkspaceFolderCreationData[], path?: URI): Promise<void> { if (path && !await this.isValidTargetWorkspacePath(path)) { - return; + return Promise.reject(null); } const remoteAuthority = this.environmentService.configuration.remoteAuthority; const untitledWorkspace = await this.workspaceService.createUntitledWorkspace(folders, remoteAuthority); @@ -288,11 +281,11 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async saveAndEnterWorkspace(path: URI): Promise<void> { if (!await this.isValidTargetWorkspacePath(path)) { - return; + return Promise.reject(null); } const workspaceIdentifier = this.getCurrentWorkspaceIdentifier(); if (!workspaceIdentifier) { - return; + return Promise.reject(null); } await this.saveWorkspaceAs(workspaceIdentifier, path); @@ -325,7 +318,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { // Return early if target is same as source if (isEqual(configPathURI, targetConfigPathURI)) { - return; + return Promise.resolve(null); } // Read the contents of the workspace file, update it to new location and save it. @@ -334,17 +327,18 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { await this.textFileService.create(targetConfigPathURI, newRawWorkspaceContents, { overwrite: true }); } - private handleWorkspaceConfigurationEditingError(error: JSONEditingError): void { + private handleWorkspaceConfigurationEditingError(error: JSONEditingError): Promise<void> { switch (error.code) { case JSONEditingErrorCode.ERROR_INVALID_FILE: this.onInvalidWorkspaceConfigurationFileError(); - break; + return Promise.resolve(); case JSONEditingErrorCode.ERROR_FILE_DIRTY: this.onWorkspaceConfigurationFileDirtyError(); - break; - default: - this.notificationService.error(error.message); + return Promise.resolve(); } + this.notificationService.error(error.message); + + return Promise.resolve(); } private onInvalidWorkspaceConfigurationFileError(): void { @@ -368,7 +362,7 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { async enterWorkspace(path: URI): Promise<void> { if (!!this.environmentService.extensionTestsLocationURI) { - throw new Error('Entering a new workspace is not possible in tests.'); + return Promise.reject(new Error('Entering a new workspace is not possible in tests.')); } const workspace = await this.workspaceService.getWorkspaceIdentifier(path); diff --git a/src/vs/workbench/test/common/notifications.test.ts b/src/vs/workbench/test/common/notifications.test.ts index 01b138d94e..95f31fe0b0 100644 --- a/src/vs/workbench/test/common/notifications.test.ts +++ b/src/vs/workbench/test/common/notifications.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemLabelKind, IStatusMessageChangeEvent, StatusMessageChangeType } from 'vs/workbench/common/notifications'; +import { NotificationsModel, NotificationViewItem, INotificationChangeEvent, NotificationChangeType, NotificationViewItemLabelKind } from 'vs/workbench/common/notifications'; import { Action } from 'vs/base/common/actions'; import { INotification, Severity } from 'vs/platform/notification/common/notification'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; @@ -132,14 +132,9 @@ suite('Notifications', () => { test('Model', () => { const model = new NotificationsModel(); - let lastNotificationEvent!: INotificationChangeEvent; + let lastEvent!: INotificationChangeEvent; model.onDidNotificationChange(e => { - lastNotificationEvent = e; - }); - - let lastStatusMessageEvent!: IStatusMessageChangeEvent; - model.onDidStatusMessageChange(e => { - lastStatusMessageEvent = e; + lastEvent = e; }); let item1: INotification = { severity: Severity.Error, message: 'Error Message', actions: { primary: [new Action('id', 'label')] } }; @@ -147,23 +142,23 @@ suite('Notifications', () => { let item2Duplicate: INotification = { severity: Severity.Warning, message: 'Warning Message', source: 'Some Source' }; let item3: INotification = { severity: Severity.Info, message: 'Info Message' }; - let item1Handle = model.addNotification(item1); - assert.equal(lastNotificationEvent.item.severity, item1.severity); - assert.equal(lastNotificationEvent.item.message.value, item1.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); + let item1Handle = model.notify(item1); + assert.equal(lastEvent.item.severity, item1.severity); + assert.equal(lastEvent.item.message.value, item1.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.ADD); - let item2Handle = model.addNotification(item2); - assert.equal(lastNotificationEvent.item.severity, item2.severity); - assert.equal(lastNotificationEvent.item.message.value, item2.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); + let item2Handle = model.notify(item2); + assert.equal(lastEvent.item.severity, item2.severity); + assert.equal(lastEvent.item.message.value, item2.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.ADD); - model.addNotification(item3); - assert.equal(lastNotificationEvent.item.severity, item3.severity); - assert.equal(lastNotificationEvent.item.message.value, item3.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); + model.notify(item3); + assert.equal(lastEvent.item.severity, item3.severity); + assert.equal(lastEvent.item.message.value, item3.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.ADD); assert.equal(model.notifications.length, 3); @@ -175,48 +170,29 @@ suite('Notifications', () => { item1Handle.close(); assert.equal(called, 1); assert.equal(model.notifications.length, 2); - assert.equal(lastNotificationEvent.item.severity, item1.severity); - assert.equal(lastNotificationEvent.item.message.value, item1.message); - assert.equal(lastNotificationEvent.index, 2); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE); + assert.equal(lastEvent.item.severity, item1.severity); + assert.equal(lastEvent.item.message.value, item1.message); + assert.equal(lastEvent.index, 2); + assert.equal(lastEvent.kind, NotificationChangeType.REMOVE); - model.addNotification(item2Duplicate); + model.notify(item2Duplicate); assert.equal(model.notifications.length, 2); - assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity); - assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.ADD); + assert.equal(lastEvent.item.severity, item2Duplicate.severity); + assert.equal(lastEvent.item.message.value, item2Duplicate.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.ADD); item2Handle.close(); assert.equal(model.notifications.length, 1); - assert.equal(lastNotificationEvent.item.severity, item2Duplicate.severity); - assert.equal(lastNotificationEvent.item.message.value, item2Duplicate.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.REMOVE); + assert.equal(lastEvent.item.severity, item2Duplicate.severity); + assert.equal(lastEvent.item.message.value, item2Duplicate.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.REMOVE); model.notifications[0].expand(); - assert.equal(lastNotificationEvent.item.severity, item3.severity); - assert.equal(lastNotificationEvent.item.message.value, item3.message); - assert.equal(lastNotificationEvent.index, 0); - assert.equal(lastNotificationEvent.kind, NotificationChangeType.CHANGE); - - const disposable = model.showStatusMessage('Hello World'); - assert.equal(model.statusMessage!.message, 'Hello World'); - assert.equal(lastStatusMessageEvent.item.message, model.statusMessage!.message); - assert.equal(lastStatusMessageEvent.kind, StatusMessageChangeType.ADD); - disposable.dispose(); - assert.ok(!model.statusMessage); - assert.equal(lastStatusMessageEvent.kind, StatusMessageChangeType.REMOVE); - - let disposable2 = model.showStatusMessage('Hello World 2'); - const disposable3 = model.showStatusMessage('Hello World 3'); - - assert.equal(model.statusMessage!.message, 'Hello World 3'); - - disposable2.dispose(); - assert.equal(model.statusMessage!.message, 'Hello World 3'); - - disposable3.dispose(); - assert.ok(!model.statusMessage); + assert.equal(lastEvent.item.severity, item3.severity); + assert.equal(lastEvent.item.message.value, item3.message); + assert.equal(lastEvent.index, 0); + assert.equal(lastEvent.kind, NotificationChangeType.CHANGE); }); }); \ No newline at end of file diff --git a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts index 605792b2e3..86d1abc0b1 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostLanguageFeatures.test.ts @@ -194,7 +194,7 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); + assert.equal(value.length, 1); }); test('CodeLens, do not resolve a resolved lens', async () => { @@ -212,8 +212,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); - const [data] = value.lenses; + assert.equal(value.length, 1); + const data = value[0]; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); assert.equal(symbol!.command!.id, 'id'); assert.equal(symbol!.command!.title, 'Title'); @@ -229,8 +229,8 @@ suite('ExtHostLanguageFeatures', function () { await rpcProtocol.sync(); const value = await getCodeLensData(model, CancellationToken.None); - assert.equal(value.lenses.length, 1); - let [data] = value.lenses; + assert.equal(value.length, 1); + let data = value[0]; const symbol = await Promise.resolve(data.provider.resolveCodeLens!(model, data.symbol, CancellationToken.None)); assert.equal(symbol!.command!.id, 'missing'); assert.equal(symbol!.command!.title, '!!MISSING: command!!'); @@ -1041,9 +1041,7 @@ suite('ExtHostLanguageFeatures', function () { disposables.push(extHost.registerDocumentLinkProvider(defaultExtension, defaultSelector, new class implements vscode.DocumentLinkProvider { provideDocumentLinks() { - const link = new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3')); - link.tooltip = 'tooltip'; - return [link]; + return [new types.DocumentLink(new types.Range(0, 0, 1, 1), URI.parse('foo:bar#3'))]; } })); @@ -1053,7 +1051,6 @@ suite('ExtHostLanguageFeatures', function () { let [first] = links; assert.equal(first.url, 'foo:bar#3'); assert.deepEqual(first.range, { startLineNumber: 1, startColumn: 1, endLineNumber: 2, endColumn: 2 }); - assert.equal(first.tooltip, 'tooltip'); }); test('Links, evil provider', async () => { diff --git a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts index 75e0ec6fdc..102eede466 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -6,11 +6,9 @@ import * as assert from 'assert'; import { MainThreadMessageService } from 'vs/workbench/api/browser/mainThreadMessageService'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions, IStatusMessageOptions } from 'vs/platform/notification/common/notification'; +import { INotificationService, INotification, NoOpNotification, INotificationHandle, Severity, IPromptChoice, IPromptOptions } from 'vs/platform/notification/common/notification'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; -import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; const emptyDialogService = new class implements IDialogService { _serviceBrand: 'dialogService'; @@ -32,7 +30,7 @@ const emptyCommandService: ICommandService = { }; const emptyNotificationService = new class implements INotificationService { - _serviceBrand: ServiceIdentifier<INotificationService>; + _serviceBrand: 'notificiationService'; notify(...args: any[]): never { throw new Error('not implemented'); } @@ -48,13 +46,11 @@ const emptyNotificationService = new class implements INotificationService { prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { throw new Error('not implemented'); } - status(message: string | Error, options?: IStatusMessageOptions): IDisposable { - return Disposable.None; - } }; class EmptyNotificationService implements INotificationService { - _serviceBrand: ServiceIdentifier<INotificationService>; + + _serviceBrand: any; constructor(private withNotify: (notification: INotification) => void) { } @@ -76,9 +72,6 @@ class EmptyNotificationService implements INotificationService { prompt(severity: Severity, message: string, choices: IPromptChoice[], options?: IPromptOptions): INotificationHandle { throw new Error('not implemented'); } - status(message: string, options?: IStatusMessageOptions): IDisposable { - return Disposable.None; - } } suite('ExtHostMessageService', function () { diff --git a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts index b8647a6fc0..a1638d7cd3 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostSearch.test.ts @@ -7,7 +7,7 @@ import * as assert from 'assert'; import { mapArrayOrNot } from 'vs/base/common/arrays'; import { CancellationTokenSource } from 'vs/base/common/cancellation'; import { isPromiseCanceledError } from 'vs/base/common/errors'; -import { DisposableStore } from 'vs/base/common/lifecycle'; +import { dispose } from 'vs/base/common/lifecycle'; import { joinPath } from 'vs/base/common/resources'; import { URI, UriComponents } from 'vs/base/common/uri'; import * as pfs from 'vs/base/node/pfs'; @@ -21,7 +21,7 @@ import * as vscode from 'vscode'; let rpcProtocol: TestRPCProtocol; let extHostSearch: ExtHostSearch; -const disposables = new DisposableStore(); +let disposables: vscode.Disposable[] = []; let mockMainThreadSearch: MockMainThreadSearch; class MockMainThreadSearch implements MainThreadSearchShape { @@ -63,12 +63,12 @@ export function extensionResultIsMatch(data: vscode.TextSearchResult): data is v suite('ExtHostSearch', () => { async function registerTestTextSearchProvider(provider: vscode.TextSearchProvider, scheme = 'file'): Promise<void> { - disposables.add(extHostSearch.registerTextSearchProvider(scheme, provider)); + disposables.push(extHostSearch.registerTextSearchProvider(scheme, provider)); await rpcProtocol.sync(); } async function registerTestFileSearchProvider(provider: vscode.FileSearchProvider, scheme = 'file'): Promise<void> { - disposables.add(extHostSearch.registerFileSearchProvider(scheme, provider)); + disposables.push(extHostSearch.registerFileSearchProvider(scheme, provider)); await rpcProtocol.sync(); } @@ -139,7 +139,7 @@ suite('ExtHostSearch', () => { }); teardown(() => { - disposables.clear(); + dispose(disposables); return rpcProtocol.sync(); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts index 06f8131bb8..20e7cb6212 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostTypes.test.ts @@ -31,7 +31,6 @@ suite('ExtHostTypes', function () { scheme: 'file', path: '/path/test.file', fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'), - _sep: isWindows ? 1 : undefined, }); assert.ok(uri.toString()); @@ -40,7 +39,6 @@ suite('ExtHostTypes', function () { scheme: 'file', path: '/path/test.file', fsPath: '/path/test.file'.replace(/\//g, isWindows ? '\\' : '/'), - _sep: isWindows ? 1 : undefined, external: 'file:///path/test.file' }); }); diff --git a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts index 2dae8ec3e9..46474373c1 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWebview.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { MainThreadWebviews } from 'vs/workbench/api/browser/mainThreadWebview'; +import { MainThreadWebviews } from 'vs/workbench/api/electron-browser/mainThreadWebview'; import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview'; import { mock } from 'vs/workbench/test/electron-browser/api/mock'; import * as vscode from 'vscode'; diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts index 532131bc72..c9640a7423 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadEditors.test.ts @@ -62,7 +62,7 @@ suite('MainThreadEditors', () => { } move(source: URI, target: URI) { movedResources.set(source, target); - return Promise.resolve(Object.create(null)); + return Promise.resolve(undefined); } models = <any>{ onModelSaved: Event.None, diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index b823d8b632..325ad75f16 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -456,9 +456,6 @@ export class TestLayoutService implements IWorkbenchLayoutService { container: HTMLElement = window.document.body; onZenModeChange: Event<boolean> = Event.None; - onCenteredLayoutChange: Event<boolean> = Event.None; - onFullscreenChange: Event<boolean> = Event.None; - onPanelPositionChange: Event<string> = Event.None; onLayout = Event.None; private _onTitleBarVisibilityChange = new Emitter<void>(); diff --git a/src/vs/workbench/workbench.main.ts b/src/vs/workbench/workbench.main.ts index 418079dcb3..3851f1e7fb 100644 --- a/src/vs/workbench/workbench.main.ts +++ b/src/vs/workbench/workbench.main.ts @@ -7,8 +7,7 @@ import 'vs/editor/editor.all'; -import 'vs/workbench/api/browser/extensionHost.contribution'; -import 'sql/workbench/api/electron-browser/extensionHost.contribution'; // {{SQL CARBON EDIT}} @anthonydresser add our extension contributions +import 'vs/workbench/api/electron-browser/extensionHost.contribution'; import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/browser/workbench.contribution'; @@ -103,8 +102,9 @@ import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService import 'vs/workbench/services/extensions/common/inactiveExtensionUrlHandler'; import 'vs/workbench/services/decorations/browser/decorationsService'; import 'vs/workbench/services/search/node/searchService'; -import 'vs/workbench/services/progress/browser/progressService'; +import 'vs/workbench/services/progress/browser/progressService2'; import 'vs/workbench/services/editor/browser/codeEditorService'; +import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import 'vs/workbench/services/extensions/electron-browser/extensionHostDebugService'; import 'vs/workbench/services/preferences/browser/preferencesService'; import 'vs/workbench/services/output/node/outputChannelModelService'; @@ -163,7 +163,6 @@ registerSingleton(IMenubarService, MenubarService); registerSingleton(IURLService, RelayURLService); registerSingleton(ITunnelService, TunnelService, true); registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); -registerSingleton(ICredentialsService, KeytarCredentialsService, true); //#endregion @@ -180,7 +179,7 @@ import { IAngularEventingService } from 'sql/platform/angularEventing/common/ang import { AngularEventingService } from 'sql/platform/angularEventing/node/angularEventingService'; import { ICapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesService'; import { CapabilitiesService } from 'sql/platform/capabilities/common/capabilitiesServiceImpl'; -import { ICredentialsService as sqlICredentialsService, CredentialsService } from 'sql/platform/credentials/common/credentialsService'; +import { ICredentialsService, CredentialsService } from 'sql/platform/credentials/common/credentialsService'; import { ISerializationService, SerializationService } from 'sql/platform/serialization/common/serializationService'; import { IMetadataService, MetadataService } from 'sql/platform/metadata/common/metadataService'; import { IObjectExplorerService, ObjectExplorerService } from 'sql/workbench/services/objectExplorer/common/objectExplorerService'; @@ -244,7 +243,7 @@ registerSingleton(ICapabilitiesService, CapabilitiesService); registerSingleton(IErrorMessageService, ErrorMessageService); registerSingleton(IConnectionDialogService, ConnectionDialogService); registerSingleton(IServerGroupController, ServerGroupController); -registerSingleton(sqlICredentialsService, CredentialsService); +registerSingleton(ICredentialsService, CredentialsService); registerSingleton(IResourceProviderService, ResourceProviderService); registerSingleton(IAccountManagementService, AccountManagementService); registerSingleton(IConnectionManagementService, ConnectionManagementService as any); @@ -299,11 +298,8 @@ import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; // Preferences -import 'vs/workbench/contrib/preferences/browser/preferences.contribution'; +import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution'; import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; -import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences'; -import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/electron-browser/preferencesSearch'; -registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); // Logs import 'vs/workbench/contrib/logs/common/logs.contribution'; @@ -437,10 +433,11 @@ import 'vs/workbench/contrib/outline/browser/outline.contribution'; // Experiments import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; +// Code Insets +import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; + // Issues import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; -import { ICredentialsService } from 'vs/platform/credentials/common/credentials'; -import { KeytarCredentialsService } from 'vs/platform/credentials/node/credentialsService'; // {{SQL CARBON EDIT}} // SQL @@ -453,6 +450,7 @@ import 'sql/workbench/parts/dataExplorer/browser/dataExplorerExtensionPoint'; import 'sql/workbench/parts/dataExplorer/electron-browser/nodeActions.contribution'; import 'sql/platform/telemetry/telemetry.contribution'; +import 'sql/workbench/api/node/sqlExtHost.contribution'; import 'sql/workbench/parts/connection/browser/connection.contribution'; import 'sql/workbench/parts/query/browser/query.contribution'; import 'sql/workbench/parts/query/common/resultsGridContribution'; diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 7762553111..0e4a8d5f5b 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -7,7 +7,7 @@ import 'vs/editor/editor.all'; -import 'vs/workbench/api/browser/extensionHost.contribution'; +// import 'vs/workbench/api/electron-browser/extensionHost.contribution'; // import 'vs/workbench/electron-browser/main.contribution'; import 'vs/workbench/browser/workbench.contribution'; @@ -90,6 +90,7 @@ import { ContextViewService } from 'vs/platform/contextview/browser/contextViewS // import { IURLService } from 'vs/platform/url/common/url'; // import { RelayURLService } from 'vs/platform/url/electron-browser/urlService'; import { IHeapService, NullHeapService } from 'vs/workbench/services/heap/common/heap'; +import { IBroadcastService, NullBroadcastService } from 'vs/workbench/services/broadcast/common/broadcast'; import { ConfigurationResolverService } from 'vs/workbench/services/configurationResolver/browser/configurationResolverService'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; @@ -100,13 +101,14 @@ import 'vs/platform/dialogs/browser/dialogService'; import 'vs/workbench/services/bulkEdit/browser/bulkEditService'; // import 'vs/workbench/services/integrity/node/integrityService'; import 'vs/workbench/services/keybinding/common/keybindingEditing'; -import 'vs/workbench/services/textMate/browser/textMateService'; +// import 'vs/workbench/services/textMate/electron-browser/textMateService'; // import 'vs/workbench/services/workspace/electron-browser/workspaceEditingService'; // import 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler'; import 'vs/workbench/services/decorations/browser/decorationsService'; // import 'vs/workbench/services/search/node/searchService'; -import 'vs/workbench/services/progress/browser/progressService'; +import 'vs/workbench/services/progress/browser/progressService2'; import 'vs/workbench/services/editor/browser/codeEditorService'; +// import 'vs/workbench/services/broadcast/electron-browser/broadcastService'; import 'vs/workbench/services/preferences/browser/preferencesService'; import 'vs/workbench/services/output/common/outputChannelModelService'; import 'vs/workbench/services/configuration/common/jsonEditingService'; @@ -126,7 +128,7 @@ import 'vs/workbench/services/mode/common/workbenchModeService'; import 'vs/workbench/services/commands/common/commandService'; import 'vs/workbench/services/themes/browser/workbenchThemeService'; // import 'vs/workbench/services/extensionManagement/node/extensionEnablementService'; -import 'vs/workbench/services/extensions/browser/extensionService'; +// import 'vs/workbench/services/extensions/electron-browser/extensionService'; // import 'vs/workbench/services/contextmenu/electron-browser/contextmenuService'; // import 'vs/workbench/services/extensionManagement/node/multiExtensionManagement'; import 'vs/workbench/services/label/common/labelService'; @@ -165,6 +167,7 @@ registerSingleton(IContextViewService, ContextViewService, true); // registerSingleton(IMenubarService, MenubarService); // registerSingleton(IURLService, RelayURLService); registerSingleton(IHeapService, NullHeapService); +registerSingleton(IBroadcastService, NullBroadcastService); registerSingleton(IContextMenuService, ContextMenuService); registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); @@ -195,11 +198,8 @@ import 'vs/workbench/contrib/telemetry/browser/telemetry.contribution'; // import 'vs/workbench/contrib/localizations/browser/localizations.contribution'; // Preferences -import 'vs/workbench/contrib/preferences/browser/preferences.contribution'; +// import 'vs/workbench/contrib/preferences/electron-browser/preferences.contribution'; import 'vs/workbench/contrib/preferences/browser/keybindingsEditorContribution'; -import { IPreferencesSearchService } from 'vs/workbench/contrib/preferences/common/preferences'; -import { PreferencesSearchService } from 'vs/workbench/contrib/preferences/browser/preferencesSearch'; -registerSingleton(IPreferencesSearchService, PreferencesSearchService, true); // Logs import 'vs/workbench/contrib/logs/common/logs.contribution'; @@ -249,8 +249,6 @@ import 'vs/workbench/contrib/url/common/url.contribution'; // Webview // import 'vs/workbench/contrib/webview/electron-browser/webview.contribution'; -registerSingleton(IWebviewService, NullWebviewService, true); -registerSingleton(IWebviewEditorService, WebviewEditorService, true); // Extensions Management // import 'vs/workbench/contrib/extensions/electron-browser/extensions.contribution'; @@ -324,13 +322,13 @@ import 'vs/workbench/contrib/welcome/overlay/browser/welcomeOverlay'; // Outline import 'vs/workbench/contrib/outline/browser/outline.contribution'; -import { IWebviewService } from 'vs/workbench/contrib/webview/common/webview'; -import { NullWebviewService } from 'vs/workbench/contrib/webview/browser/webviewService'; -import { IWebviewEditorService, WebviewEditorService } from 'vs/workbench/contrib/webview/browser/webviewEditorService'; // Experiments // import 'vs/workbench/contrib/experiments/electron-browser/experiments.contribution'; +// Code Insets +// import 'vs/workbench/contrib/codeinset/electron-browser/codeInset.contribution'; + // Issues // import 'vs/workbench/contrib/issue/electron-browser/issue.contribution'; diff --git a/test/smoke/README.md b/test/smoke/README.md index b5be966e51..3eed271d35 100644 --- a/test/smoke/README.md +++ b/test/smoke/README.md @@ -15,14 +15,11 @@ yarn smoketest # Build yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --stable-build PATH_TO_LAST_STABLE_BUILD_PARENT_FOLDER - -# Remote -yarn smoketest --build PATH_TO_NEW_BUILD_PARENT_FOLDER --remote ``` ### Run for a release -You must always run the smoketest version which matches the release you are testing. So, if you want to run the smoketest for a release build (e.g. `release/1.22`), you need that version of the smoke tests too: +You must always run the smoketest version which matches the release you are testing. So, if you want to run the smoketest for a release build (eg `release/1.22`), you need that version of the smoke tests too: ```bash git checkout release/1.22 diff --git a/test/smoke/package.json b/test/smoke/package.json index e19de8f9de..00b04f8453 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -17,12 +17,12 @@ "@types/mkdirp": "0.5.1", "@types/mocha": "2.2.41", "@types/ncp": "2.0.1", - "@types/node": "^10.14.8", + "@types/node": "8.0.33", "@types/rimraf": "2.0.2", "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "4.2.3", + "electron": "3.1.8", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", diff --git a/test/smoke/src/application.ts b/test/smoke/src/application.ts index f2f346ebef..7c60cabdfb 100644 --- a/test/smoke/src/application.ts +++ b/test/smoke/src/application.ts @@ -47,10 +47,6 @@ export class Application { return this.options.logger; } - get remote(): boolean { - return !!this.options.remote; - } - private _workspacePathOrFolder: string; get workspacePathOrFolder(): string { return this._workspacePathOrFolder; @@ -146,12 +142,8 @@ export class Application { await this.code.waitForWindowIds(ids => ids.length > 0); await this.code.waitForElement('.monaco-workbench'); - if (this.remote) { - await this.code.waitForElement('.monaco-workbench .statusbar-item.statusbar-entry a[title="Editing on TestResolver"]'); - } - // wait a bit, since focus might be stolen off widgets - // as soon as they open (e.g. quick open) + // as soon as they open (eg quick open) await new Promise(c => setTimeout(c, 1000)); } } diff --git a/test/smoke/src/areas/editor/peek.ts b/test/smoke/src/areas/editor/peek.ts index 1cb127456e..baa00aff0f 100644 --- a/test/smoke/src/areas/editor/peek.ts +++ b/test/smoke/src/areas/editor/peek.ts @@ -10,7 +10,7 @@ export class References { private static readonly REFERENCES_WIDGET = '.monaco-editor .zone-widget .zone-widget-container.peekview-widget.reference-zone-widget.results-loaded'; private static readonly REFERENCES_TITLE_FILE_NAME = `${References.REFERENCES_WIDGET} .head .peekview-title .filename`; private static readonly REFERENCES_TITLE_COUNT = `${References.REFERENCES_WIDGET} .head .peekview-title .meta`; - private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .highlight`; + private static readonly REFERENCES = `${References.REFERENCES_WIDGET} .body .ref-tree.inline .monaco-list-row .reference`; constructor(private code: Code) { } diff --git a/test/smoke/src/areas/extensions/extensions.test.ts b/test/smoke/src/areas/extensions/extensions.test.ts index d664cd8108..5f1a5ac694 100644 --- a/test/smoke/src/areas/extensions/extensions.test.ts +++ b/test/smoke/src/areas/extensions/extensions.test.ts @@ -20,10 +20,6 @@ export function setup() { await app.workbench.extensions.installExtension('michelkaporin.vscode-smoketest-check', 'vscode-smoketest-check'); await app.workbench.extensions.waitForExtensionsViewlet(); - - if (app.remote) { - await app.reload(); - } await app.workbench.quickopen.runCommand('Smoke Test Check'); await app.workbench.statusbar.waitForStatusbarText('smoke test', 'VS Code Smoke Test Check'); }); diff --git a/test/smoke/src/areas/multiroot/multiroot.test.ts b/test/smoke/src/areas/multiroot/multiroot.test.ts index ca98e172aa..996792effa 100644 --- a/test/smoke/src/areas/multiroot/multiroot.test.ts +++ b/test/smoke/src/areas/multiroot/multiroot.test.ts @@ -47,8 +47,7 @@ export function setup() { const app = this.app as Application; await app.workbench.quickopen.openQuickOpen('*.*'); - // TODO roblourens: Go to files finds welcome page: issue 74875 - await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6 || names.length === 7); + await app.workbench.quickopen.waitForQuickOpenElements(names => names.length === 6); await app.workbench.quickopen.closeQuickOpen(); }); diff --git a/test/smoke/src/areas/statusbar/statusbar.ts b/test/smoke/src/areas/statusbar/statusbar.ts index b6919965ab..b3aecf0c4b 100644 --- a/test/smoke/src/areas/statusbar/statusbar.ts +++ b/test/smoke/src/areas/statusbar/statusbar.ts @@ -48,7 +48,7 @@ export class StatusBar { case StatusBarElement.SYNC_STATUS: return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-sync`; case StatusBarElement.PROBLEMS_STATUS: - return `${this.mainSelector} ${this.leftSelector} .octicon.octicon-error`; + return `${this.mainSelector} ${this.leftSelector} .task-statusbar-item[title="Problems"]`; case StatusBarElement.SELECTION_STATUS: return `${this.mainSelector} ${this.rightSelector} .editor-status-selection`; case StatusBarElement.INDENTATION_STATUS: diff --git a/test/smoke/src/vscode/code.ts b/test/smoke/src/vscode/code.ts index ac38b41e98..f6398446d1 100644 --- a/test/smoke/src/vscode/code.ts +++ b/test/smoke/src/vscode/code.ts @@ -7,7 +7,6 @@ import * as path from 'path'; import * as cp from 'child_process'; import * as os from 'os'; import * as fs from 'fs'; -import * as mkdirp from 'mkdirp'; import { tmpName } from 'tmp'; import { IDriver, connect as connectDriver, IDisposable, IElement, Thenable } from './driver'; import { Logger } from '../logger'; @@ -124,8 +123,6 @@ export async function spawn(options: SpawnOptions): Promise<Code> { '--driver', handle ]; - const env = process.env; - if (options.remote) { // Replace workspace path with URI args.shift(); @@ -142,9 +139,6 @@ export async function spawn(options: SpawnOptions): Promise<Code> { } } args.push('--enable-proposed-api=vscode.vscode-test-resolver'); - const remoteDataDir = `${options.userDataDir}-server`; - mkdirp.sync(remoteDataDir); - env['TESTRESOLVER_DATA_FOLDER'] = remoteDataDir; } if (!codePath) { @@ -163,7 +157,7 @@ export async function spawn(options: SpawnOptions): Promise<Code> { args.push(...options.extraArgs); } - const spawnOptions: cp.SpawnOptions = { env }; + const spawnOptions: cp.SpawnOptions = {}; const child = cp.spawn(electronPath, args, spawnOptions); diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index cdcb6f7dad..5e1fd36aa4 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -44,15 +44,15 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@types/node@^10.12.18": - version "10.12.18" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.12.18.tgz#1d3ca764718915584fcd9f6344621b7672665c67" - integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== +"@types/node@8.0.33": + version "8.0.33" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.33.tgz#1126e94374014e54478092830704f6ea89df04cd" + integrity sha512-vmCdO8Bm1ExT+FWfC9sd9r4jwqM7o97gGy2WBshkkXbf/2nLAJQUrZfIhw27yVOtLUev6kSZc4cav/46KbDd8A== -"@types/node@^10.14.8": - version "10.14.8" - resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.8.tgz#fe444203ecef1162348cd6deb76c62477b2cc6e9" - integrity sha512-I4+DbJEhLEg4/vIy/2gkWDvXBOOtPKV9EnLhYjMoqxcRW+TTZtUftkHktz/a8suoD5mUL7m6ReLrkPvSsCQQmw== +"@types/node@^8.0.24": + version "8.10.23" + resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.23.tgz#e5ccfdafff42af5397c29669b6d7d65f7d629a00" + integrity sha512-aEp5ZTLr4mYhR9S85cJ+sEYkcsgFY10N1Si5m49iTAVzanZXOwp/pgw6ibFLKXxpflqm71aSWZCRtnTXXO56gA== "@types/rimraf@2.0.2": version "2.0.2" @@ -596,12 +596,12 @@ electron-download@^4.1.0: semver "^5.4.1" sumchecker "^2.0.2" -electron@4.2.3: - version "4.2.3" - resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.3.tgz#5d45da9dd5ae97269dbee2623840da808c72d29d" - integrity sha512-nx+jHxj2eNhaYHXFGdzr7zgSphpVHEU9WAu6qqEUsQ936X3c6bQ5Bdg08KbHZj+cyRRQ06JMu6/ILh5pWrDZaA== +electron@3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/electron/-/electron-3.1.8.tgz#01b0b147dfcca47967ff07dbf72bf5e96125a2ac" + integrity sha512-1MiFoMzxGaR0wDfwFE5Ydnuk6ry/4lKgF0c+NFyEItxM/WyEHNZPNjJAeKJ+M/0sevmZ+6W4syNZnQL5M3GgsQ== dependencies: - "@types/node" "^10.12.18" + "@types/node" "^8.0.24" electron-download "^4.1.0" extract-zip "^1.0.3" diff --git a/yarn.lock b/yarn.lock index 704d8d8910..53c2a681f7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -990,18 +990,11 @@ binaryextensions@~1.0.0: resolved "https://registry.yarnpkg.com/binaryextensions/-/binaryextensions-1.0.1.tgz#1e637488b35b58bda5f4774bf96a5212a8c90755" integrity sha1-HmN0iLNbWL2l9HdL+WpSEqjJB1U= -bindings@^1.2.1: +bindings@^1.2.1, bindings@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.3.0.tgz#b346f6ecf6a95f5a815c5839fc7cdb22502f1ed7" integrity sha512-DpLh5EzMR2kzvX1KIlVC0VkC3iZtHKTgdtZ0a3pglBZdaQFjt5S9g9xd1lE+YvXyfd6mtCeRnrUfOLYiTMlNSw== -bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - bl@^1.0.0: version "1.2.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" @@ -1554,6 +1547,14 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" +clean-css@3.4.6: + version "3.4.6" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.6.tgz#fcb4f17057ddb7f8721616f70b07b294d95ffc45" + integrity sha1-/LTxcFfdt/hyFhb3CweylNlf/EU= + dependencies: + commander "2.8.x" + source-map "0.4.x" + cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" @@ -1776,6 +1777,13 @@ commander@2.3.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873" integrity sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM= +commander@2.8.x: + version "2.8.1" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4" + integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ= + dependencies: + graceful-readlink ">= 1.0.0" + commander@^2.12.1, commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -3237,13 +3245,6 @@ fd-slicer@~1.0.1: dependencies: pend "~1.2.0" -fd-slicer@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" - integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= - dependencies: - pend "~1.2.0" - figures@^1.3.5: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" @@ -3267,11 +3268,6 @@ file-entry-cache@^2.0.0: flat-cache "^1.2.1" object-assign "^4.0.1" -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - filename-regex@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" @@ -3870,6 +3866,11 @@ graceful-fs@4.1.11, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" integrity sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg= +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU= + growl@1.9.2: version "1.9.2" resolved "https://registry.yarnpkg.com/growl/-/growl-1.9.2.tgz#0ea7743715db8d8de2c5ede1775e1b45ac85c02f" @@ -6062,7 +6063,7 @@ mute-stream@0.0.7, mute-stream@~0.0.4: resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= -nan@2.8.0: +nan@2.8.0, nan@^2.8.0: version "2.8.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.8.0.tgz#ed715f3fe9de02b57a5e6252d90a96675e1f085a" integrity sha1-7XFfP+neArV6XmJS2QqWZ14fCFo= @@ -6077,7 +6078,7 @@ nan@^2.12.1: resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== -nan@^2.13.2, nan@^2.14.0: +nan@^2.13.2: version "2.14.0" resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== @@ -6217,10 +6218,10 @@ node-pre-gyp@^0.10.0: semver "^5.3.0" tar "^4" -node-pty@0.9.0-beta17: - version "0.9.0-beta17" - resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta17.tgz#9b490df86a8124dea595e9fbedeaaf4b2eedbbcb" - integrity sha512-E94XwIs3JxLKAboquHY9Kytbbj/T/tJtRpQoAUdfPE7UXRta/NV+xdmRNhZkeU9jCji+plm656GbYFievgNPkQ== +node-pty@0.9.0-beta9: + version "0.9.0-beta9" + resolved "https://registry.yarnpkg.com/node-pty/-/node-pty-0.9.0-beta9.tgz#75cffcf4026f543475c115f017ca7fe66cf6e7fe" + integrity sha512-h6e8jUikGSZwqt1JHmzT5Zi0fdUCultX/BWrS35suTaZNJm/YSJA2QDG9HTVoSA6dhRvtFoaGiBtgbX9uZKe6w== dependencies: nan "^2.13.2" @@ -6495,11 +6496,6 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -onigasm-umd@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/onigasm-umd/-/onigasm-umd-2.2.2.tgz#b989d762df61f899a3052ac794a50bd93fe20257" - integrity sha512-v2eMOJu7iE444L2iJN+U6s6s5S0y7oj/N0DAkrd6wokRtTVoq/v/yaDI1lIqFrTeJbNtqNzYvguDF5yNzW3Rvw== - oniguruma@^7.0.0: version "7.0.2" resolved "https://registry.yarnpkg.com/oniguruma/-/oniguruma-7.0.2.tgz#a5c922cf7066da1dbcc60f6385a90437a83f8d0b" @@ -8441,18 +8437,18 @@ source-map-url@^0.4.0: resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= -source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -source-map@^0.4.4: +source-map@0.4.x, source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" integrity sha1-66T12pwNyZneaAMti092FzZSA2s= dependencies: amdefine ">=0.0.4" +source-map@0.6.1, source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + source-map@^0.5.1, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1: version "0.5.7" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" @@ -8470,14 +8466,14 @@ sparkles@^1.0.0: resolved "https://registry.yarnpkg.com/sparkles/-/sparkles-1.0.0.tgz#1acbbfb592436d10bbe8f785b7cc6f82815012c3" integrity sha1-Gsu/tZJDbRC76PeFt8xvgoFQEsM= -spdlog@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.9.0.tgz#c85dd9d0b9cd385f6f3f5b92dc9d2e1691092b5c" - integrity sha512-AeLWPCYjGi4w5DfpXFKb9pCdgMe4gFBMroGfgwXiNfzwmcNYGoFQkIuD1MChZBR1Iwrx0nGhsTSHFslt/qfTAQ== +spdlog@0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/spdlog/-/spdlog-0.8.1.tgz#dfb3f3422ab3efe32be79e4769b95440ed72699f" + integrity sha512-W0s8IOXpn86md+8PJ4mJeB/22thykzH5YaNc3Rgnql4x4/zFIhvNiEx6/a1arnqvmJF0HtRO0Ehlswg0WcwTLQ== dependencies: - bindings "^1.5.0" + bindings "^1.3.0" mkdirp "^0.5.1" - nan "^2.14.0" + nan "^2.8.0" spdx-correct@~1.0.0: version "1.0.2" @@ -9253,10 +9249,10 @@ typescript-formatter@7.1.0: commandpost "^1.0.0" editorconfig "^0.15.0" -typescript@3.5.1: - version "3.5.1" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.5.1.tgz#ba72a6a600b2158139c5dd8850f700e231464202" - integrity sha512-64HkdiRv1yYZsSe4xC1WVgamNigVYjlssIoaH2HcZF0+ijsk5YK2g0G34w9wJkze8+5ow4STd22AynfO6ZYYLw== +typescript@3.4.5: + version "3.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.4.5.tgz#2d2618d10bb566572b8d7aad5180d84257d70a99" + integrity sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw== typescript@^2.6.2: version "2.6.2" @@ -9743,10 +9739,10 @@ vscode-chokidar@1.6.5: optionalDependencies: vscode-fsevents "0.3.10" -vscode-debugprotocol@1.35.0: - version "1.35.0" - resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.35.0.tgz#565140cd42945e30c6c85cafb38c631457d4a46c" - integrity sha512-+OMm11R1bGYbpIJ5eQIkwoDGFF4GvBz3Ztl6/VM+/RNNb2Gjk2c0Ku+oMmfhlTmTlPCpgHBsH4JqVCbUYhu5bA== +vscode-debugprotocol@1.34.0: + version "1.34.0" + resolved "https://registry.yarnpkg.com/vscode-debugprotocol/-/vscode-debugprotocol-1.34.0.tgz#aef63274166ccbc6d1d68e68c7d7f6d013802f08" + integrity sha512-tcMThtgk9TUtE8zzAIwPvHZfgnEYnVa7cI3YaQk/o54Q9cme+TLd/ao60a6ycj5rCrI/B5r/mAfeK5EKSItm7g== vscode-fsevents@0.3.10: version "0.3.10" @@ -9773,10 +9769,10 @@ vscode-nls-dev@3.2.5: xml2js "^0.4.19" yargs "^10.1.1" -vscode-nsfw@1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vscode-nsfw/-/vscode-nsfw-1.1.2.tgz#9cb9073b5854386801afe41f7152f721b4ea9e80" - integrity sha512-J0So+JNK/5kQboTO1hKNk4ie/wwUegrJilYSY5sVxU9JJlo3aQdP0zi2NtU8CEK3kkN6qRp0MbXCzbT0LKGorg== +vscode-nsfw@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vscode-nsfw/-/vscode-nsfw-1.1.1.tgz#7c3febe153677c5850b197a0b64a197cd11e95c7" + integrity sha512-Wg3vzN1U3T6P1uE13LdVVRIhdy7XWnWkwmAXhkLsIkH2QY0E/pvNDRLrwAMMW6GC1Fvvbxm3hzdIrCmr7Hq3FA== dependencies: fs-extra "^7.0.0" lodash.isinteger "^4.0.4" @@ -9805,10 +9801,10 @@ vscode-sqlite3@4.0.7: dependencies: nan "~2.10.0" -vscode-textmate@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.1.1.tgz#857e836fbc13a376ec624242437e1747d79610a9" - integrity sha512-xBjq9LH6fMhWDhIVkbKlB1JeCu6lT3FI/QKN24Xi4RKPBUm16IhHTqs6Q6SUGewkNsFZGkb1tJdZsuMnlmVpgw== +vscode-textmate@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/vscode-textmate/-/vscode-textmate-4.0.1.tgz#6c36f28e9059ce12bc34907f7a33ea43166b26a8" + integrity sha512-gHTXTj04TUgbjB8y7pkVwxOiuCuD6aU5gnFzIByQuqdgFpe/bJaaEIS4geGjbjWbd1XJh6zG1EthLfpNaXEqUw== dependencies: oniguruma "^7.0.0" @@ -9826,6 +9822,11 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" +vscode-xterm@3.14.0-beta3: + version "3.14.0-beta3" + resolved "https://registry.yarnpkg.com/vscode-xterm/-/vscode-xterm-3.14.0-beta3.tgz#e2624e231f7b940edd0675eb569a10b3af75e29d" + integrity sha512-80Bbq6R4q0xABJl7COwE1DSNoJp3H2LyfKDHSbh1PwUY+6wofpW8/V9xSYELizeg3lVAd7mcEKW+rG+sY1hpqA== + vso-node-api@6.1.2-preview: version "6.1.2-preview" resolved "https://registry.yarnpkg.com/vso-node-api/-/vso-node-api-6.1.2-preview.tgz#aab3546df2451ecd894e071bb99b5df19c5fa78f" @@ -10095,21 +10096,6 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.1.0-beta5: - version "0.1.0-beta5" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.1.0-beta5.tgz#a9ad03d8fc02f8dfaab57809d446d4100b194fda" - integrity sha512-+50eYWs6D77kDHOFxaVss6r4lRskvkrmEXiz5x5aAgO07YIhOfQ3S0RFnQPch2kQ1mS66hsRnnUf0NGNEIZ1+A== - -xterm-addon-web-links@0.1.0-beta9: - version "0.1.0-beta9" - resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta9.tgz#8d30e41f54887ba668974d736488518322bea2c5" - integrity sha512-2UbhFqYMNGY2Eg6jrn+j2jpK2gGRqluiF5I++lSDYbKrxtfj7+WJZYhBzb0EeE7gbzDfcGZqsoueM/q+fAWB8Q== - -xterm@3.15.0-beta23: - version "3.15.0-beta23" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta23.tgz#a10b47bf3ebf30df253f7a7dac60c97f74e171f0" - integrity sha512-bMesTUsJP5M2Jhxe6u2FXuzQ3+R997eN8E6ike+0rbijnGLy2Sz+kZbNZQlBjCYO3jEEscRvaBsfiDcNQQVefA== - y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -10223,7 +10209,7 @@ yauzl@2.4.1: dependencies: fd-slicer "~1.0.1" -yauzl@^2.2.1, yauzl@^2.3.1: +yauzl@^2.2.1, yauzl@^2.3.1, yauzl@^2.9.1: version "2.9.1" resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.9.1.tgz#a81981ea70a57946133883f029c5821a89359a7f" integrity sha1-qBmB6nCleUYTOIPwKcWCGok1mn8= @@ -10231,14 +10217,6 @@ yauzl@^2.2.1, yauzl@^2.3.1: buffer-crc32 "~0.2.3" fd-slicer "~1.0.1" -yauzl@^2.9.2: - version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" - integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= - dependencies: - buffer-crc32 "~0.2.3" - fd-slicer "~1.1.0" - yazl@^2.2.1, yazl@^2.2.2, yazl@^2.4.3: version "2.4.3" resolved "https://registry.yarnpkg.com/yazl/-/yazl-2.4.3.tgz#ec26e5cc87d5601b9df8432dbdd3cd2e5173a071"