From 1d56a17f32bb0211e0e760d4edfff09bd6a2a287 Mon Sep 17 00:00:00 2001 From: Anthony Dresser Date: Sun, 28 Jul 2019 15:15:24 -0700 Subject: [PATCH] Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 (#6516) * Merge from vscode 2cfc8172e533e50c90e6a3152f6bfb1f82f963f3 * fix tests --- .vscode/settings.json | 5 +- .yarnrc | 2 +- build/azure-pipelines/distro-build.yml | 6 +- build/gulpfile.reh.js | 2 +- build/lib/extensions.js | 2 +- build/lib/extensions.ts | 2 +- build/lib/typings/gulp-remote-src.d.ts | 4 +- build/monaco/monaco.d.ts.recipe | 2 + build/monaco/monaco.usage.recipe | 2 +- build/package.json | 6 +- build/yarn.lock | 39 +- cgmanifest.json | 4 +- extensions/git/src/api/api1.ts | 10 +- extensions/git/src/api/git.d.ts | 4 + extensions/git/src/commands.ts | 6 +- extensions/git/src/model.ts | 40 +- extensions/git/src/repository.ts | 26 +- .../server/package.json | 2 +- .../server/src/jsonServerMain.ts | 3 +- .../json-language-features/server/yarn.lock | 5 + .../workspace.tasks.test.ts | 63 + .../testWorkspace/.vscode/settings.json | 8 + .../testWorkspace/files-exclude/file.txt | 1 + .../testWorkspace/search-exclude/file.txt | 1 + extensions/vscode-test-resolver/package.json | 6 +- .../xml/xml.language-configuration.json | 47 +- package.json | 8 +- remote/package.json | 4 +- remote/yarn.lock | 16 +- resources/completions/zsh/_code | 1 + resources/win32/bin/code.sh | 3 +- .../nodeActions.contribution.ts | 6 +- .../parts/query/browser/query.contribution.ts | 2 +- src/typings/electron.d.ts | 73 +- src/typings/xterm.d.ts | 53 +- src/vs/base/browser/browser.ts | 2 +- src/vs/base/browser/dom.ts | 2 +- src/vs/base/browser/mouseEvent.ts | 6 +- .../browser/ui/centered/centeredViewLayout.ts | 2 +- src/vs/base/browser/ui/grid/grid.ts | 109 +- src/vs/base/browser/ui/grid/gridview.ts | 37 +- src/vs/base/browser/ui/list/listWidget.ts | 2 +- src/vs/base/browser/ui/list/rangeMap.ts | 2 +- .../browser/ui/scrollbar/scrollableElement.ts | 3 +- src/vs/base/browser/ui/splitview/splitview.ts | 80 +- src/vs/base/browser/ui/tree/abstractTree.ts | 2 +- src/vs/base/browser/ui/tree/asyncDataTree.ts | 4 +- .../browser/ui/tree/compressedObjectTree.ts | 56 + .../ui/tree/compressedObjectTreeModel.ts | 32 +- src/vs/base/browser/ui/tree/dataTree.ts | 2 +- src/vs/base/browser/ui/tree/indexTree.ts | 2 +- src/vs/base/browser/ui/tree/objectTree.ts | 14 +- .../base/browser/ui/tree/objectTreeModel.ts | 17 +- src/vs/base/common/event.ts | 14 + src/vs/base/common/filters.ts | 2 +- src/vs/base/common/glob.ts | 1 - src/vs/base/common/json.ts | 8 +- src/vs/base/test/browser/ui/grid/grid.test.ts | 13 - .../test/browser/ui/grid/gridview.test.ts | 22 +- src/vs/base/test/browser/ui/grid/util.ts | 5 +- .../ui/tree/compressedObjectTreeModel.test.ts | 10 +- src/vs/base/test/common/filters.test.ts | 15 + .../sharedProcess/sharedProcessMain.ts | 4 +- src/vs/code/electron-main/app.ts | 12 +- src/vs/code/node/cliProcessMain.ts | 19 +- .../editor/browser/controller/mouseHandler.ts | 2 +- .../editor/browser/controller/mouseTarget.ts | 7 +- src/vs/editor/browser/editorExtensions.ts | 23 +- .../editor/browser/widget/codeEditorWidget.ts | 5 +- src/vs/editor/browser/widget/media/editor.css | 8 +- .../common/config/commonEditorConfig.ts | 4 +- src/vs/editor/common/controller/cursor.ts | 124 +- .../common/controller/cursorTypeOperations.ts | 44 +- src/vs/editor/common/core/range.ts | 26 + src/vs/editor/common/model/intervalTree.ts | 3 +- src/vs/editor/common/model/textModelSearch.ts | 6 + .../services/markerDecorationsServiceImpl.ts | 3 + .../common/standalone/standaloneEnums.ts | 3 +- src/vs/editor/contrib/clipboard/clipboard.ts | 6 - .../contrib/documentSymbols/outlineTree.ts | 4 +- src/vs/editor/contrib/find/findController.ts | 14 +- src/vs/editor/contrib/find/findModel.ts | 13 +- src/vs/editor/contrib/find/findState.ts | 21 + src/vs/editor/contrib/find/findWidget.css | 21 + src/vs/editor/contrib/find/findWidget.ts | 38 +- src/vs/editor/contrib/find/replacePattern.ts | 18 +- .../editor/contrib/find/simpleFindWidget.ts | 9 +- .../contrib/find/test/replacePattern.test.ts | 22 + .../editor/contrib/indentation/indentation.ts | 6 +- .../suggest/suggestCommitCharacters.ts | 7 + .../editor/contrib/suggest/suggestWidget.ts | 61 +- .../test/wordOperations.test.ts | 16 + .../contrib/wordOperations/wordOperations.ts | 2 +- .../standalone/browser/simpleServices.ts | 8 +- .../standalone/browser/standaloneServices.ts | 4 +- .../test/browser/controller/cursor.test.ts | 105 +- .../controller/cursorMoveCommand.test.ts | 16 +- .../editor/test/browser/editorTestServices.ts | 6 +- .../browser/services/openerService.test.ts | 1 + .../test/common/model/textModelSearch.test.ts | 19 + src/vs/monaco.d.ts | 13 +- .../common/abstractAccessibilityService.ts | 43 + .../accessibility/common/accessibility.ts | 3 + .../common/accessibilityService.ts | 26 +- .../browser/contextScopedHistoryWidget.ts | 6 +- src/vs/platform/commands/common/commands.ts | 3 + .../test/node/configurationService.test.ts | 3 +- .../platform/contextkey/common/contextkey.ts | 412 +- .../contextkey/test/common/contextkey.test.ts | 50 +- .../driver/electron-browser/driver.ts | 2 +- .../environment/common/environment.ts | 1 + src/vs/platform/environment/node/argv.ts | 1 + .../common/extensionGalleryService.ts | 3 +- .../keybinding/common/keybindingResolver.ts | 40 +- .../common/abstractKeybindingService.test.ts | 1 + .../test/common/keybindingResolver.test.ts | 83 +- src/vs/platform/list/browser/listService.ts | 8 +- src/vs/platform/markers/common/markers.ts | 1 + src/vs/platform/product/common/product.ts | 15 +- .../remote/browser/browserSocketFactory.ts | 146 + .../remote/browser/browserWebSocketFactory.ts | 89 - .../remote/common/remoteAgentConnection.ts | 10 +- src/vs/platform/remote/common/remoteHosts.ts | 12 + ...bSocketFactory.ts => nodeSocketFactory.ts} | 4 +- src/vs/platform/request/common/request.ts | 4 +- .../platform/telemetry/common/gdprTypings.ts | 2 +- .../telemetry/common/telemetryService.ts | 20 +- .../telemetry/common/telemetryUtils.ts | 8 +- .../telemetry/node/appInsightsAppender.ts | 2 +- .../platform/telemetry/node/telemetryIpc.ts | 2 +- .../appInsightsAppender.test.ts | 2 +- .../electron-browser/telemetryService.test.ts | 2 +- .../electron-main/updateService.win32.ts | 7 +- src/vs/vscode.proposed.d.ts | 181 +- .../api/browser/mainThreadCommands.ts | 14 + .../api/browser/mainThreadDebugService.ts | 6 +- .../api/browser/mainThreadTerminalService.ts | 27 +- .../api/browser/mainThreadWorkspace.ts | 9 +- .../workbench/api/common/extHost.protocol.ts | 22 +- .../workbench/api/common/extHostCommands.ts | 21 +- .../api/common/extHostTypeConverters.ts | 7 +- src/vs/workbench/api/common/extHostTypes.ts | 9 +- .../workbench/api/common/extHostWorkspace.ts | 14 +- src/vs/workbench/api/node/extHost.api.impl.ts | 27 +- .../workbench/api/node/extHostDebugService.ts | 74 +- .../api/node/extHostExtensionService.ts | 9 - src/vs/workbench/api/node/extHostTask.ts | 4 +- .../api/node/extHostTerminalService.ts | 114 +- src/vs/workbench/browser/contextkeys.ts | 6 +- src/vs/workbench/browser/layout.ts | 6 +- src/vs/workbench/browser/legacyLayout.ts | 10 +- src/vs/workbench/browser/part.ts | 14 +- .../parts/activitybar/activitybarActions.ts | 14 +- .../parts/activitybar/activitybarPart.ts | 22 +- .../workbench/browser/parts/compositePart.ts | 1 + .../parts/editor/breadcrumbsControl.ts | 10 +- .../browser/parts/editor/breadcrumbsPicker.ts | 18 +- .../parts/editor/editor.contribution.ts | 2 +- .../browser/parts/editor/editorPart.ts | 49 +- .../parts/notifications/notificationsList.ts | 2 +- .../browser/parts/panel/panelPart.ts | 24 +- .../parts/quickinput/quickInputList.ts | 2 +- .../browser/parts/sidebar/sidebarPart.ts | 18 +- .../browser/parts/statusbar/statusbarPart.ts | 3 +- .../browser/parts/views/customView.ts | 6 +- src/vs/workbench/browser/parts/views/views.ts | 32 +- .../browser/parts/views/viewsViewlet.ts | 12 +- src/vs/workbench/browser/web.main.ts | 2 +- .../codeEditor/browser/WordWrap_16x.svg | 1 - .../codeEditor/browser/toggleWordWrap.ts | 10 +- .../codeEditor/browser/word-wrap-dark.svg | 3 + .../codeEditor/browser/word-wrap-light.svg | 3 + .../contrib/comments/browser/commentNode.ts | 118 +- .../comments/browser/commentThreadWidget.ts | 2 +- .../comments/browser/commentsTreeViewer.ts | 2 +- .../contrib/comments/browser/media/review.css | 2 +- .../contrib/comments/common/commentModel.ts | 4 + .../contrib/debug/browser/breakpointsView.ts | 2 +- .../contrib/debug/browser/callStackView.ts | 2 +- .../debug/browser/debug.contribution.ts | 2 +- .../browser/debugConfigurationManager.ts | 6 +- .../contrib/debug/browser/debugHover.ts | 2 +- .../contrib/debug/browser/debugSession.ts | 4 +- .../debug/browser/loadedScriptsView.ts | 2 +- .../contrib/debug/browser/rawDebugSession.ts | 23 +- .../workbench/contrib/debug/browser/repl.ts | 21 +- .../contrib/debug/browser/variablesView.ts | 2 +- .../debug/browser/watchExpressionsView.ts | 2 +- .../workbench/contrib/debug/common/debug.ts | 11 +- .../contrib/debug/common/debugger.ts | 5 +- .../contrib/debug/node/telemetryApp.ts | 2 +- .../workbench/contrib/debug/node/terminals.ts | 38 +- .../debug/test/browser/debugModel.test.ts | 4 +- .../browser/extensions.contribution.ts | 10 +- .../extensions/browser/extensionsActions.ts | 182 +- .../extensions/browser/extensionsViewlet.ts | 21 +- .../browser/extensionsWorkbenchService.ts | 17 + .../browser/remoteExtensionsInstaller.ts | 44 + .../electron-browser/extensionTipsService.ts | 228 +- .../runtimeExtensionsEditor.ts | 2 +- .../extensionsActions.test.ts | 157 +- .../files/browser/fileActions.contribution.ts | 2 +- .../files/browser/media/explorerviewlet.css | 5 +- .../browser/media/files-activity-bar.svg | 2 +- .../files/browser/views/explorerView.ts | 2 +- .../files/browser/views/openEditorsView.ts | 2 +- .../contrib/markers/browser/markersPanel.ts | 2 +- .../contrib/outline/browser/outlinePanel.ts | 3 +- .../preferences/browser/keybindingsEditor.ts | 13 +- .../browser/preferences.contribution.ts | 4 +- .../preferences/browser/preferencesEditor.ts | 59 +- .../browser/preferencesRenderers.ts | 37 +- .../electron-browser/remote.contribution.ts | 55 +- .../browser/resourceServiceWorker.ts | 14 +- .../browser/resourceServiceWorkerClient.ts | 50 +- .../browser/resourceServiceWorkerMain.ts | 2 +- .../scm/browser/media/scm-activity-bar.svg | 11 +- .../contrib/scm/browser/scm.contribution.ts | 4 +- .../contrib/scm/browser/scmViewlet.ts | 4 +- .../browser/media/search-activity-bar.svg | 2 +- .../contrib/search/browser/replaceService.ts | 12 +- .../search/browser/search.contribution.ts | 2 +- .../contrib/search/browser/searchActions.ts | 8 +- .../search/browser/searchResultsView.ts | 18 +- .../contrib/search/browser/searchView.ts | 19 +- .../contrib/search/common/searchModel.ts | 128 +- .../search/test/browser/searchActions.test.ts | 2 +- .../search/test/common/searchModel.test.ts | 2 +- .../search/test/common/searchResult.test.ts | 43 +- .../stats/electron-browser/workspaceStats.ts | 10 +- .../electron-browser/workspaceStatsService.ts | 34 +- .../tasks/browser/terminalTaskSystem.ts | 2 +- .../browser/addons/navigationModeAddon.ts | 106 + .../terminal/browser/terminal.contribution.ts | 20 +- .../terminal/browser/terminalActions.ts | 71 +- .../terminal/browser/terminalFindWidget.ts | 6 +- .../terminal/browser/terminalInstance.ts | 42 +- .../browser/terminalProcessManager.ts | 15 +- .../terminal/browser/terminalService.ts | 5 +- .../contrib/terminal/browser/terminalTab.ts | 6 +- .../contrib/terminal/common/terminal.ts | 46 +- .../terminal/common/terminalCommands.ts | 3 + .../terminal/common/terminalEnvironment.ts | 1 + .../common/terminalProcessExtHostProxy.ts | 14 +- .../terminal/common/terminalService.ts | 57 +- .../contrib/update/electron-browser/update.ts | 65 +- .../contrib/watermark/browser/watermark.ts | 2 +- .../webview/browser/webviewEditorService.ts | 2 +- .../contrib/webview/browser/webviewElement.ts | 2 +- .../contrib/webview/common/webview.ts | 2 +- .../electron-browser/webviewElement.ts | 2 +- .../walkThrough/browser/walkThroughPart.ts | 6 - .../node/accessibilityService.ts | 16 +- .../commands/common/commandService.ts | 6 +- .../configuration/browser/configuration.ts | 78 +- .../browser/configurationService.ts | 12 +- .../configuration/common/configuration.ts | 39 +- .../browser/configurationResolverService.ts | 6 +- .../configurationResolverService.test.ts | 1 + .../editor/common/editorGroupsService.ts | 2 +- .../common/extensionManagementService.ts | 6 +- .../extensions/browser/extensionService.ts | 3 +- .../common/inactiveExtensionUrlHandler.ts | 60 +- .../common/remoteExtensionHostClient.ts | 6 +- .../electron-browser/extensionService.ts | 7 +- .../keybinding/browser/keybindingService.ts | 4 +- .../services/layout/browser/layoutService.ts | 6 + .../preferences/browser/preferencesService.ts | 68 +- .../preferences/common/preferences.ts | 2 +- .../preferences/common/preferencesModels.ts | 1 + .../remote/browser/remoteAgentServiceImpl.ts | 13 +- .../common/abstractRemoteAgentService.ts | 8 +- .../remote/common/remoteAgentService.ts | 6 +- .../remoteAgentServiceImpl.ts | 12 +- .../services/remote/node/tunnelService.ts | 4 +- .../telemetry/browser/telemetryService.ts | 2 +- .../browser/abstractTextMateService.ts | 25 +- .../textMate/browser/textMateService.ts | 6 +- .../electron-browser/textMateService.ts | 4 +- src/vs/workbench/test/browser/part.test.ts | 5 +- .../api/extHostMessagerService.test.ts | 1 + .../api/extHostWorkspace.test.ts | 30 +- .../api/mainThreadWorkspace.test.ts | 8 +- .../workbench/test/workbenchTestServices.ts | 6 +- src/vs/workbench/workbench.web.api.ts | 6 + test/electron/renderer.html | 2 +- test/smoke/package.json | 2 +- test/smoke/yarn.lock | 8 +- test/tree/public/compressed.json | 15620 ++++++++++++++++ test/tree/public/index.html | 74 +- test/tree/tree.js | 24 + yarn.lock | 55 +- 292 files changed, 19784 insertions(+), 1873 deletions(-) create mode 100644 extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts create mode 100644 extensions/vscode-api-tests/testWorkspace/.vscode/settings.json create mode 100644 extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt create mode 100644 extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt create mode 100644 src/vs/base/browser/ui/tree/compressedObjectTree.ts delete mode 100644 src/vs/base/test/browser/ui/grid/grid.test.ts create mode 100644 src/vs/platform/accessibility/common/abstractAccessibilityService.ts create mode 100644 src/vs/platform/remote/browser/browserSocketFactory.ts delete mode 100644 src/vs/platform/remote/browser/browserWebSocketFactory.ts rename src/vs/platform/remote/node/{nodeWebSocketFactory.ts => nodeSocketFactory.ts} (89%) delete mode 100644 src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg create mode 100644 src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg create mode 100644 src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg create mode 100644 src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts create mode 100644 src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts create mode 100644 test/tree/public/compressed.json create mode 100644 test/tree/tree.js diff --git a/.vscode/settings.json b/.vscode/settings.json index 3fa04b1ee9..1a760bdda6 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -59,5 +59,6 @@ "git.ignoreLimitWarning": true, "remote.extensionKind": { "msjsdiag.debugger-for-chrome": "workspace" - } -} + }, + "files.insertFinalNewline": true +} \ No newline at end of file diff --git a/.yarnrc b/.yarnrc index 441b5a2e69..c45abdbaca 100644 --- a/.yarnrc +++ b/.yarnrc @@ -1,3 +1,3 @@ disturl "https://atom.io/download/electron" -target "4.2.5" +target "4.2.7" runtime "electron" diff --git a/build/azure-pipelines/distro-build.yml b/build/azure-pipelines/distro-build.yml index 4057894f02..62ee67ad1c 100644 --- a/build/azure-pipelines/distro-build.yml +++ b/build/azure-pipelines/distro-build.yml @@ -31,12 +31,12 @@ steps: git remote add distro "https://github.com/$VSCODE_MIXIN_REPO.git" git fetch distro - # Push master branch into master and oss/master - git push distro origin/master:refs/heads/master origin/master:refs/heads/oss/master + # Push master branch into oss/master + git push distro origin/master:refs/heads/oss/master # Push every release branch into oss/release git for-each-ref --format="%(refname:short)" refs/remotes/origin/release/* | sed 's/^origin\/\(.*\)$/\0:refs\/heads\/oss\/\1/' | xargs git push distro git merge $(node -p "require('./package.json').distro") - displayName: Sync & Merge Distro \ No newline at end of file + displayName: Sync & Merge Distro diff --git a/build/gulpfile.reh.js b/build/gulpfile.reh.js index 4739923fda..c5c4dbf66f 100644 --- a/build/gulpfile.reh.js +++ b/build/gulpfile.reh.js @@ -17,7 +17,7 @@ const gunzip = require('gulp-gunzip'); const untar = require('gulp-untar'); const File = require('vinyl'); const fs = require('fs'); -const remote = require('gulp-remote-src'); +const remote = require('gulp-remote-retry-src'); const rename = require('gulp-rename'); const filter = require('gulp-filter'); const cp = require('child_process'); diff --git a/build/lib/extensions.js b/build/lib/extensions.js index bf9360e21c..9aa43bc202 100644 --- a/build/lib/extensions.js +++ b/build/lib/extensions.js @@ -13,7 +13,7 @@ const File = require("vinyl"); const vsce = require("vsce"); const stats_1 = require("./stats"); const util2 = require("./util"); -const remote = require("gulp-remote-src"); +const remote = require("gulp-remote-retry-src"); const vzip = require('gulp-vinyl-zip'); const filter = require("gulp-filter"); const rename = require("gulp-rename"); diff --git a/build/lib/extensions.ts b/build/lib/extensions.ts index e90b9552a4..d05ad07029 100644 --- a/build/lib/extensions.ts +++ b/build/lib/extensions.ts @@ -13,7 +13,7 @@ import * as File from 'vinyl'; import * as vsce from 'vsce'; import { createStatsStream } from './stats'; import * as util2 from './util'; -import remote = require('gulp-remote-src'); +import remote = require('gulp-remote-retry-src'); const vzip = require('gulp-vinyl-zip'); import filter = require('gulp-filter'); import rename = require('gulp-rename'); diff --git a/build/lib/typings/gulp-remote-src.d.ts b/build/lib/typings/gulp-remote-src.d.ts index 6ea57f84fe..ff9026b79b 100644 --- a/build/lib/typings/gulp-remote-src.d.ts +++ b/build/lib/typings/gulp-remote-src.d.ts @@ -1,4 +1,4 @@ -declare module 'gulp-remote-src' { +declare module 'gulp-remote-retry-src' { import stream = require("stream"); @@ -20,4 +20,4 @@ declare module 'gulp-remote-src' { } export = remote; -} \ No newline at end of file +} diff --git a/build/monaco/monaco.d.ts.recipe b/build/monaco/monaco.d.ts.recipe index a379a7522a..a4cf5a9cf0 100644 --- a/build/monaco/monaco.d.ts.recipe +++ b/build/monaco/monaco.d.ts.recipe @@ -5,6 +5,8 @@ declare namespace monaco { + // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. + export type Thenable = PromiseLike; export interface IDisposable { diff --git a/build/monaco/monaco.usage.recipe b/build/monaco/monaco.usage.recipe index 13290a7abb..f1a74a25e3 100644 --- a/build/monaco/monaco.usage.recipe +++ b/build/monaco/monaco.usage.recipe @@ -30,7 +30,7 @@ import * as editorAPI from './vs/editor/editor.api'; a = (>b).type; a = (b).start; a = (b).end; - a = (>b).getProxyObject; // IWorkerClient + a = (>b).getProxyObject; // IWorkerClient a = create1; a = create2; a = (b).extensionId; diff --git a/build/package.json b/build/package.json index 4fb67a9474..cc2e8369f4 100644 --- a/build/package.json +++ b/build/package.json @@ -20,7 +20,7 @@ "@types/minimatch": "^3.0.3", "@types/minimist": "^1.2.0", "@types/mocha": "2.2.39", - "@types/node": "8.0.33", + "@types/node": "^10.14.8", "@types/pump": "^1.0.1", "@types/request": "^2.47.0", "@types/rimraf": "^2.0.2", @@ -29,7 +29,7 @@ "@types/uglify-es": "^3.0.0", "@types/underscore": "^1.8.9", "@types/xml2js": "0.0.33", - "applicationinsights": "1.0.6", + "applicationinsights": "1.0.8", "azure-storage": "^2.1.0", "del": "^3.0.0", "documentdb": "1.13.0", @@ -44,7 +44,7 @@ "service-downloader": "github:anthonydresser/service-downloader#0.1.5", "typescript": "3.5.2", "vsce": "1.48.0", - "vscode-telemetry-extractor": "1.4.3", + "vscode-telemetry-extractor": "^1.5.1", "xml2js": "^0.4.17" }, "scripts": { diff --git a/build/yarn.lock b/build/yarn.lock index bbb907bc75..bb9873134a 100644 --- a/build/yarn.lock +++ b/build/yarn.lock @@ -187,10 +187,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-8.0.51.tgz#b31d716fb8d58eeb95c068a039b9b6292817d5fb" integrity sha512-El3+WJk2D/ppWNd2X05aiP5l2k4EwF7KwheknQZls+I26eSICoWRhRIJ56jGgw2dqNGQ5LtNajmBU2ajS28EvQ== -"@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.13" + resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.13.tgz#ac786d623860adf39a3f51d629480aacd6a6eec7" + integrity sha512-yN/FNNW1UYsRR1wwAoyOwqvDuLDtVXnaJTZ898XIw/Q5cCaeVAlVwvsmXLX5PuiScBYwZsZU4JYSHB3TvfdwvQ== "@types/pump@^1.0.1": version "1.0.1" @@ -374,10 +374,10 @@ anymatch@^2.0.0: micromatch "^3.1.4" normalize-path "^2.1.1" -applicationinsights@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.6.tgz#bc201810de91cea910dab34e8ad35ecde488edeb" - integrity sha512-VQT3kBpJVPw5fCO5n+WUeSx0VHjxFtD7znYbILBlVgOS9/cMDuGFmV2Br3ObzFyZUDGNbEfW36fD1y2/vAiCKw== +applicationinsights@1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/applicationinsights/-/applicationinsights-1.0.8.tgz#db6e3d983cf9f9405fe1ee5ba30ac6e1914537b5" + integrity sha512-KzOOGdphOS/lXWMFZe5440LUdFbrLpMvh2SaRxn7BmiI550KAoSb2gIhiq6kJZ9Ir3AxRRztjhzif+e5P5IXIg== dependencies: diagnostic-channel "0.2.0" diagnostic-channel-publishers "0.2.1" @@ -1847,7 +1847,12 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= @@ -3388,7 +3393,7 @@ tough-cookie@~2.3.3: dependencies: punycode "^1.4.1" -ts-morph@^3.1.2: +ts-morph@^3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/ts-morph/-/ts-morph-3.1.3.tgz#bbfa1d14481ee23bdd1c030340ccf4a243cfc844" integrity sha512-CwjgyJTtd3f8vBi7Vr0IOgdOY6Wi/Tq0MhieXOE2B5ns5WWRD7BwMNHtv+ZufKI/S2U/lMrh+Q3bOauE4tsv2g== @@ -3613,19 +3618,19 @@ vsce@1.48.0: yauzl "^2.3.1" yazl "^2.2.2" -vscode-ripgrep@^1.4.0: +vscode-ripgrep@^1.5.5: version "1.5.5" resolved "https://registry.yarnpkg.com/vscode-ripgrep/-/vscode-ripgrep-1.5.5.tgz#24c0e9cb356cf889c98e15ecb58f9cf654a1d961" integrity sha512-OrPrAmcun4+uZAuNcQvE6CCPskh+5AsjANod/Q3zRcJcGNxgoOSGlQN9RPtatkUNmkN8Nn8mZBnS1jMylu/dKg== -vscode-telemetry-extractor@1.4.3: - version "1.4.3" - resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.4.3.tgz#e4af380beb4e2a63d6e4fa819b25ba7ef6dc4a10" - integrity sha512-OFklPErZnUBjrKte3hg+irQXue5rzgz4qnvE8kdaOnW1E/wynHUEXW9t5vF5q0hu2lodpGMkybwLkSjONZVzvg== +vscode-telemetry-extractor@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/vscode-telemetry-extractor/-/vscode-telemetry-extractor-1.5.1.tgz#67249e4ca9c65a21800ca53880732f8cef98d0fa" + integrity sha512-B5SnEdRiDrI4o6NMG9iHmengoaW1rxUQmS/sCaripgnchm+P79JURmKxhfXr5eRo4Mr1QSenFT/SDNaEop7aoQ== dependencies: command-line-args "^5.1.1" - ts-morph "^3.1.2" - vscode-ripgrep "^1.4.0" + ts-morph "^3.1.3" + vscode-ripgrep "^1.5.5" vso-node-api@6.1.2-preview: version "6.1.2-preview" diff --git a/cgmanifest.json b/cgmanifest.json index b8c4f3bfef..638303702a 100644 --- a/cgmanifest.json +++ b/cgmanifest.json @@ -60,12 +60,12 @@ "git": { "name": "electron", "repositoryUrl": "https://github.com/electron/electron", - "commitHash": "5d67ec3da5376a5058990e8a9557bc9124ad59a8" + "commitHash": "36ea114ac0616e469e75ae94e6d53af48925e036" } }, "isOnlyProductionDependency": true, "license": "MIT", - "version": "4.2.5" + "version": "4.2.7" }, { "component": { diff --git a/extensions/git/src/api/api1.ts b/extensions/git/src/api/api1.ts index 0f0df0650d..6e47ea6eaf 100644 --- a/extensions/git/src/api/api1.ts +++ b/extensions/git/src/api/api1.ts @@ -5,7 +5,7 @@ import { Model } from '../model'; import { Repository as BaseRepository, Resource } from '../repository'; -import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions } from './git'; +import { InputBox, Git, API, Repository, Remote, RepositoryState, Branch, Ref, Submodule, Commit, Change, RepositoryUIState, Status, LogOptions, APIState } from './git'; import { Event, SourceControlInputBox, Uri, SourceControl } from 'vscode'; import { mapEvent } from '../util'; @@ -214,6 +214,14 @@ export class ApiImpl implements API { readonly git = new ApiGit(this._model); + get state(): APIState { + return this._model.state; + } + + get onDidChangeState(): Event { + return this._model.onDidChangeState; + } + get onDidOpenRepository(): Event { return mapEvent(this._model.onDidOpenRepository, r => new ApiRepository(r)); } diff --git a/extensions/git/src/api/git.d.ts b/extensions/git/src/api/git.d.ts index 9e82d769f1..e4d0510675 100644 --- a/extensions/git/src/api/git.d.ts +++ b/extensions/git/src/api/git.d.ts @@ -176,7 +176,11 @@ export interface Repository { log(options?: LogOptions): Promise; } +export type APIState = 'uninitialized' | 'initialized'; + export interface API { + readonly state: APIState; + readonly onDidChangeState: Event; readonly git: Git; readonly repositories: Repository[]; readonly onDidOpenRepository: Event; diff --git a/extensions/git/src/commands.ts b/extensions/git/src/commands.ts index 5efd4ccede..27bbef5eca 100755 --- a/extensions/git/src/commands.ts +++ b/extensions/git/src/commands.ts @@ -1115,7 +1115,7 @@ export class CommandCenter { if (scmResources.length === 1) { if (untrackedCount > 0) { - message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(scmResources[0].resourceUri.fsPath)); + message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(scmResources[0].resourceUri.fsPath)); yes = localize('delete file', "Delete file"); } else { if (scmResources[0].type === Status.DELETED) { @@ -1134,7 +1134,7 @@ export class CommandCenter { } if (untrackedCount > 0) { - message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!", untrackedCount)}`; + message = `${message}\n\n${localize('warn untracked', "This will DELETE {0} untracked files!\nThis is IRREVERSIBLE!\nThese files will be FOREVER LOST.", untrackedCount)}`; } } @@ -1175,7 +1175,7 @@ export class CommandCenter { await repository.clean(resources.map(r => r.resourceUri)); return; } else if (resources.length === 1) { - const message = localize('confirm delete', "Are you sure you want to DELETE {0}?", path.basename(resources[0].resourceUri.fsPath)); + const message = localize('confirm delete', "Are you sure you want to DELETE {0}?\nThis is IRREVERSIBLE!\nThis file will be FOREVER LOST.", path.basename(resources[0].resourceUri.fsPath)); const yes = localize('delete file', "Delete file"); const pick = await window.showWarningMessage(message, { modal: true }, yes); diff --git a/extensions/git/src/model.ts b/extensions/git/src/model.ts index 94cf12a025..83fa11915c 100644 --- a/extensions/git/src/model.ts +++ b/extensions/git/src/model.ts @@ -12,7 +12,7 @@ import * as path from 'path'; import * as fs from 'fs'; import * as nls from 'vscode-nls'; import { fromGitUri } from './uri'; -import { GitErrorCodes } from './api/git'; +import { GitErrorCodes, APIState as State } from './api/git'; const localize = nls.loadMessageBundle(); @@ -63,15 +63,22 @@ export class Model { private possibleGitRepositoryPaths = new Set(); + private _onDidChangeState = new EventEmitter(); + readonly onDidChangeState = this._onDidChangeState.event; + + private _state: State = 'uninitialized'; + get state(): State { return this._state; } + + setState(state: State): void { + this._state = state; + this._onDidChangeState.fire(state); + } + private disposables: Disposable[] = []; constructor(readonly git: Git, private globalState: Memento, private outputChannel: OutputChannel) { workspace.onDidChangeWorkspaceFolders(this.onDidChangeWorkspaceFolders, this, this.disposables); - this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }); - window.onDidChangeVisibleTextEditors(this.onDidChangeVisibleTextEditors, this, this.disposables); - this.onDidChangeVisibleTextEditors(window.visibleTextEditors); - workspace.onDidChangeConfiguration(this.onDidChangeConfiguration, this, this.disposables); const fsWatcher = workspace.createFileSystemWatcher('**'); @@ -82,7 +89,15 @@ export class Model { const onPossibleGitRepositoryChange = filterEvent(onGitRepositoryChange, uri => !this.getRepository(uri)); onPossibleGitRepositoryChange(this.onPossibleGitRepositoryChange, this, this.disposables); - this.scanWorkspaceFolders(); + this.doInitialScan().finally(() => this.setState('initialized')); + } + + private async doInitialScan(): Promise { + await Promise.all([ + this.onDidChangeWorkspaceFolders({ added: workspace.workspaceFolders || [], removed: [] }), + this.onDidChangeVisibleTextEditors(window.visibleTextEditors), + this.scanWorkspaceFolders() + ]); } /** @@ -157,8 +172,8 @@ export class Model { .filter(r => !activeRepositories.has(r!.repository)) .filter(r => !(workspace.workspaceFolders || []).some(f => isDescendant(f.uri.fsPath, r!.repository.root))) as OpenRepository[]; - possibleRepositoryFolders.forEach(p => this.openRepository(p.uri.fsPath)); openRepositoriesToDispose.forEach(r => r.dispose()); + await Promise.all(possibleRepositoryFolders.map(p => this.openRepository(p.uri.fsPath))); } private onDidChangeConfiguration(): void { @@ -175,7 +190,7 @@ export class Model { openRepositoriesToDispose.forEach(r => r.dispose()); } - private onDidChangeVisibleTextEditors(editors: TextEditor[]): void { + private async onDidChangeVisibleTextEditors(editors: TextEditor[]): Promise { const config = workspace.getConfiguration('git'); const autoRepositoryDetection = config.get('autoRepositoryDetection'); @@ -183,7 +198,7 @@ export class Model { return; } - editors.forEach(editor => { + await Promise.all(editors.map(async editor => { const uri = editor.document.uri; if (uri.scheme !== 'file') { @@ -196,8 +211,8 @@ export class Model { return; } - this.openRepository(path.dirname(uri.fsPath)); - }); + await this.openRepository(path.dirname(uri.fsPath)); + })); } @sequentialize @@ -236,6 +251,7 @@ export class Model { const repository = new Repository(this.git.open(repositoryRoot, dotGit), this.globalState, this.outputChannel); this.open(repository); + await repository.status(); } catch (err) { if (err.gitErrorCode === GitErrorCodes.NotAGitRepository) { return; @@ -421,4 +437,4 @@ export class Model { this.possibleGitRepositoryPaths.clear(); this.disposables = dispose(this.disposables); } -} \ No newline at end of file +} diff --git a/extensions/git/src/repository.ts b/extensions/git/src/repository.ts index 4afe4fd8af..c2a86a45ed 100644 --- a/extensions/git/src/repository.ts +++ b/extensions/git/src/repository.ts @@ -519,8 +519,8 @@ class DotGitWatcher implements IFileWatcher { this.transientDisposables.push(upstreamWatcher); upstreamWatcher.event(this.emitter.fire, this.emitter, this.transientDisposables); } catch (err) { - if (env.logLevel <= LogLevel.Info) { - this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}'. Ref is most likely packed.`); + if (env.logLevel <= LogLevel.Error) { + this.outputChannel.appendLine(`Failed to watch ref '${upstreamPath}', is most likely packed.\n${err.stack || err}`); } } } @@ -651,19 +651,30 @@ export class Repository implements Disposable { const onWorkspaceRepositoryFileChange = filterEvent(onWorkspaceFileChange, uri => isDescendant(repository.root, uri.fsPath)); const onWorkspaceWorkingTreeFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => !/\/\.git($|\/)/.test(uri.path)); - const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); - this.disposables.push(dotGitFileWatcher); + let onDotGitFileChange: Event; + + try { + const dotGitFileWatcher = new DotGitWatcher(this, outputChannel); + onDotGitFileChange = dotGitFileWatcher.event; + this.disposables.push(dotGitFileWatcher); + } catch (err) { + if (env.logLevel <= LogLevel.Error) { + outputChannel.appendLine(`Failed to watch '${this.dotGit}', reverting to legacy API file watched. Some events might be lost.\n${err.stack || err}`); + } + + onDotGitFileChange = filterEvent(onWorkspaceRepositoryFileChange, uri => /\/\.git($|\/)/.test(uri.path)); + } // FS changes should trigger `git status`: // - any change inside the repository working tree // - any change whithin the first level of the `.git` folder, except the folder itself and `index.lock` - const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event); + const onFileChange = anyEvent(onWorkspaceWorkingTreeFileChange, onDotGitFileChange); onFileChange(this.onFileChange, this, this.disposables); // Relevate repository changes should trigger virtual document change events - dotGitFileWatcher.event(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); + onDotGitFileChange(this._onDidChangeRepository.fire, this._onDidChangeRepository, this.disposables); - this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, dotGitFileWatcher.event, outputChannel)); + this.disposables.push(new FileEventLogger(onWorkspaceWorkingTreeFileChange, onDotGitFileChange, outputChannel)); const root = Uri.file(repository.root); this._sourceControl = scm.createSourceControl('git', 'Git', root); @@ -713,7 +724,6 @@ export class Repository implements Disposable { this.disposables.push(progressManager); this.updateCommitTemplate(); - this.status(); } validateInput(text: string, position: number): SourceControlInputBoxValidation | undefined { diff --git a/extensions/json-language-features/server/package.json b/extensions/json-language-features/server/package.json index 061cb69249..68e6a00553 100644 --- a/extensions/json-language-features/server/package.json +++ b/extensions/json-language-features/server/package.json @@ -17,7 +17,7 @@ "vscode-json-languageservice": "^3.3.0", "vscode-languageserver": "^5.3.0-next.8", "vscode-nls": "^4.1.1", - "vscode-uri": "^2.0.1" + "vscode-uri": "^2.0.3" }, "devDependencies": { "@types/mocha": "2.2.33", diff --git a/extensions/json-language-features/server/src/jsonServerMain.ts b/extensions/json-language-features/server/src/jsonServerMain.ts index 54f24e1986..a078940ae4 100644 --- a/extensions/json-language-features/server/src/jsonServerMain.ts +++ b/extensions/json-language-features/server/src/jsonServerMain.ts @@ -154,7 +154,8 @@ connection.onInitialize((params: InitializeParams): InitializeResult => { documentSymbolProvider: true, documentRangeFormattingProvider: false, colorProvider: {}, - foldingRangeProvider: true + foldingRangeProvider: true, + selectionRangeProvider: true }; return { capabilities }; diff --git a/extensions/json-language-features/server/yarn.lock b/extensions/json-language-features/server/yarn.lock index 1bb198a521..13ab8c59ab 100644 --- a/extensions/json-language-features/server/yarn.lock +++ b/extensions/json-language-features/server/yarn.lock @@ -134,3 +134,8 @@ vscode-uri@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.1.tgz#5448e4f77d21d93ffa34b96f84c6c5e09e3f5a9b" integrity sha512-s/k0zsYr6y+tsocFyxT/+G5aq8mEdpDZuph3LZ+UmCs7LNhx/xomiCy5kyP+jOAKC7RMCUvb6JbPD1/TgAvq0g== + +vscode-uri@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/vscode-uri/-/vscode-uri-2.0.3.tgz#25e5f37f552fbee3cec7e5f80cef8469cefc6543" + integrity sha512-4D3DI3F4uRy09WNtDGD93H9q034OHImxiIcSq664Hq1Y1AScehlP3qqZyTkX/RWxeu0MRMHGkrxYqm2qlDF/aw== diff --git a/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts new file mode 100644 index 0000000000..2e3c1e2924 --- /dev/null +++ b/extensions/vscode-api-tests/src/singlefolder-tests/workspace.tasks.test.ts @@ -0,0 +1,63 @@ +/*--------------------------------------------------------------------------------------------- + * 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 * as vscode from 'vscode'; + +suite('workspace-namespace', () => { + + suite('Tasks', () => { + + test('CustomExecution2 task should start and shutdown successfully', (done) => { + interface CustomTestingTaskDefinition extends vscode.TaskDefinition { + /** + * One of the task properties. This can be used to customize the task in the tasks.json + */ + customProp1: string; + } + const taskType: string = 'customTesting'; + const taskName = 'First custom task'; + const reg1 = vscode.window.onDidOpenTerminal(term => { + reg1.dispose(); + const reg2 = term.onDidWriteData(e => { + reg2.dispose(); + assert.equal(e, 'testing\r\n'); + term.dispose(); + }); + }); + const taskProvider = vscode.tasks.registerTaskProvider(taskType, { + provideTasks: () => { + const result: vscode.Task[] = []; + const kind: CustomTestingTaskDefinition = { + type: taskType, + customProp1: 'testing task one' + }; + const writeEmitter = new vscode.EventEmitter(); + const execution = new vscode.CustomExecution2((): Thenable => { + const pty: vscode.Pseudoterminal = { + onDidWrite: writeEmitter.event, + open: () => { + writeEmitter.fire('testing\r\n'); + }, + close: () => { + taskProvider.dispose(); + done(); + } + }; + return Promise.resolve(pty); + }); + const task = new vscode.Task2(kind, vscode.TaskScope.Workspace, taskName, taskType, execution); + result.push(task); + return result; + }, + resolveTask(_task: vscode.Task): vscode.Task | undefined { + assert.fail('resolveTask should not trigger during the test'); + return undefined; + } + }); + vscode.commands.executeCommand('workbench.action.tasks.runTask', `${taskType}: ${taskName}`); + }); + }); +}); diff --git a/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json new file mode 100644 index 0000000000..e9f6fb8215 --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/.vscode/settings.json @@ -0,0 +1,8 @@ +{ + "search.exclude": { + "**/search-exclude/**": true + }, + "files.exclude": { + "**/files-exclude/**": true + } +} \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt new file mode 100644 index 0000000000..1a010b1c0f --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/files-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt new file mode 100644 index 0000000000..1a010b1c0f --- /dev/null +++ b/extensions/vscode-api-tests/testWorkspace/search-exclude/file.txt @@ -0,0 +1 @@ +file \ No newline at end of file diff --git a/extensions/vscode-test-resolver/package.json b/extensions/vscode-test-resolver/package.json index 167df92db2..0d93c4ea6d 100644 --- a/extensions/vscode-test-resolver/package.json +++ b/extensions/vscode-test-resolver/package.json @@ -53,17 +53,17 @@ "statusBar/windowIndicator": [ { "command": "vscode-testresolver.newWindow", - "when": "!remoteAuthority", + "when": "!remoteName", "group": "9_local_testresolver@2" }, { "command": "vscode-testresolver.showLog", - "when": "remoteAuthority =~ /^test\\+.*$/", + "when": "remoteName == test", "group": "1_remote_testresolver_open@3" }, { "command": "vscode-testresolver.newWindow", - "when": "remoteAuthority =~ /^test\\+.*$/", + "when": "remoteName == test", "group": "1_remote_testresolver_open@1" } ] diff --git a/extensions/xml/xml.language-configuration.json b/extensions/xml/xml.language-configuration.json index faaa59c1cd..702b6dc6eb 100644 --- a/extensions/xml/xml.language-configuration.json +++ b/extensions/xml/xml.language-configuration.json @@ -1,31 +1,34 @@ { "comments": { - "lineComment": "", - "blockComment": [""] + "blockComment": [ "" ] }, "brackets": [ - ["<", ">"] + [""], + ["<", ">"], + ["{", "}"], + ["(", ")"] ], "autoClosingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "", "notIn": [ "comment", "string" ]}, + { "open": "", "notIn": [ "comment", "string" ]} ], "surroundingPairs": [ - ["<", ">"], - ["'", "'"], - ["\"", "\""] - ] - - // enhancedBrackets: [{ - // tokenType: 'tag.tag-$1.xml', - // openTrigger: '>', - // open: /<(\w[\w\d]*)([^\/>]*(?!\/)>)[^<>]*$/i, - // closeComplete: '', - // closeTrigger: '>', - // close: /<\/(\w[\w\d]*)\s*>$/i - // }], - - // autoClosingPairs: [['\'', '\''], ['"', '"'] ] - + { "open": "'", "close": "'" }, + { "open": "\"", "close": "\"" }, + { "open": "{", "close": "}"}, + { "open": "[", "close": "]"}, + { "open": "(", "close": ")" }, + { "open": "<", "close": ">" } + ], + "folding": { + "markers": { + "start": "^\\s*", + "end": "^\\s*" + } + } } diff --git a/package.json b/package.json index cf2121fe1b..e336503187 100644 --- a/package.json +++ b/package.json @@ -76,8 +76,8 @@ "vscode-ripgrep": "^1.5.5", "vscode-sqlite3": "4.0.8", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta71", - "xterm-addon-search": "0.2.0-beta2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3", @@ -124,7 +124,7 @@ "gulp-gunzip": "^1.0.0", "gulp-json-editor": "^2.5.0", "gulp-plumber": "^1.2.0", - "gulp-remote-src": "^0.4.4", + "gulp-remote-retry-src": "^0.6.0", "gulp-rename": "^1.2.0", "gulp-replace": "^0.5.4", "gulp-shell": "^0.6.5", @@ -192,4 +192,4 @@ "windows-mutex": "0.3.0", "windows-process-tree": "0.2.4" } -} \ No newline at end of file +} diff --git a/remote/package.json b/remote/package.json index 081eb5c607..34ffee1a4b 100644 --- a/remote/package.json +++ b/remote/package.json @@ -20,8 +20,8 @@ "vscode-proxy-agent": "0.4.0", "vscode-ripgrep": "^1.5.5", "vscode-textmate": "^4.2.2", - "xterm": "3.15.0-beta71", - "xterm-addon-search": "0.2.0-beta2", + "xterm": "3.15.0-beta89", + "xterm-addon-search": "0.2.0-beta3", "xterm-addon-web-links": "0.1.0-beta10", "yauzl": "^2.9.2", "yazl": "^2.4.3" diff --git a/remote/yarn.lock b/remote/yarn.lock index 3ed8f02de3..1c4e700f49 100644 --- a/remote/yarn.lock +++ b/remote/yarn.lock @@ -1149,20 +1149,20 @@ vscode-windows-registry@1.0.1: dependencies: nan "^2.12.1" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta71: - version "3.15.0-beta71" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta71.tgz#2728c9800ca3b08423e835e9504bd1f4b5de6253" - integrity sha512-8M/cLaxZ+iDopRxLPdPfKuDGaNNyYTdCeytdxjMSH0N7dZzbx6fbaEygQdCrV5pO9cGnT92MefSjVPGRXRiBLA== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== yauzl@^2.9.2: version "2.10.0" diff --git a/resources/completions/zsh/_code b/resources/completions/zsh/_code index 054ab351e9..265c199f62 100644 --- a/resources/completions/zsh/_code +++ b/resources/completions/zsh/_code @@ -17,6 +17,7 @@ arguments=( '(- *)'{--telemetry}'[Shows all telemetry events which VS code collects.]' '--extensions-dir[set the root path for extensions]:root path:_directories' '--list-extensions[list the installed extensions]' + '--category[filters instaled extension list by category, when using --list-extension]' '--show-versions[show versions of installed extensions, when using --list-extension]' '--install-extension[install an extension]:id or path:_files -g "*.vsix(-.)"' '--uninstall-extension[uninstall an extension]:id or path:_files -g "*.vsix(-.)"' diff --git a/resources/win32/bin/code.sh b/resources/win32/bin/code.sh index 23a4001a47..9c5eb1c8b1 100644 --- a/resources/win32/bin/code.sh +++ b/resources/win32/bin/code.sh @@ -34,7 +34,8 @@ if grep -qi Microsoft /proc/version; then if [ -n "$WSL_EXT_WLOC" ]; then # replace \r\n with \n in WSL_EXT_WLOC WSL_CODE=$(wslpath -u "${WSL_EXT_WLOC%%[[:cntrl:]]}")/scripts/wslCode.sh - "$WSL_CODE" "$COMMIT" "$QUALITY" "$ELECTRON" "$APP_NAME" "$DATAFOLDER" "$@" + WIN_CODE_CMD=$(wslpath -w "$VSCODE_PATH/bin/$APP_NAME.cmd") + "$WSL_CODE" "$COMMIT" "$QUALITY" "$WIN_CODE_CMD" "$APP_NAME" "$DATAFOLDER" "$@" exit $? fi else diff --git a/src/sql/workbench/parts/dataExplorer/electron-browser/nodeActions.contribution.ts b/src/sql/workbench/parts/dataExplorer/electron-browser/nodeActions.contribution.ts index 984f8cad47..76977ab650 100644 --- a/src/sql/workbench/parts/dataExplorer/electron-browser/nodeActions.contribution.ts +++ b/src/sql/workbench/parts/dataExplorer/electron-browser/nodeActions.contribution.ts @@ -31,7 +31,7 @@ MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, { title: localize('disconnect', "Disconnect") }, when: ContextKeyExpr.and(NodeContextKey.IsConnected, - new ContextKeyNotEqualsExpr('nodeType', NodeType.Folder)) + ContextKeyNotEqualsExpr.create('nodeType', NodeType.Folder)) }); MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, { @@ -214,7 +214,7 @@ MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, { }, when: ContextKeyExpr.and(MssqlNodeContext.NodeProvider.isEqualTo(mssqlProviderName), MssqlNodeContext.IsWindows, - new ContextKeyRegexExpr('nodeType', /^(Database|Table|Column|Index|Statistic|View|ServerLevelLogin|ServerLevelServerRole|ServerLevelCredential|ServerLevelServerAudit|ServerLevelServerAuditSpecification|StoredProcedure|ScalarValuedFunction|TableValuedFunction|AggregateFunction|Synonym|Assembly|UserDefinedDataType|UserDefinedType|UserDefinedTableType|Sequence|User|DatabaseRole|ApplicationRole|Schema|SecurityPolicy|ServerLevelLinkedServer)$/)) + ContextKeyRegexExpr.create('nodeType', /^(Database|Table|Column|Index|Statistic|View|ServerLevelLogin|ServerLevelServerRole|ServerLevelCredential|ServerLevelServerAudit|ServerLevelServerAuditSpecification|StoredProcedure|ScalarValuedFunction|TableValuedFunction|AggregateFunction|Synonym|Assembly|UserDefinedDataType|UserDefinedType|UserDefinedTableType|Sequence|User|DatabaseRole|ApplicationRole|Schema|SecurityPolicy|ServerLevelLinkedServer)$/)) }); //////////////// Scripting Actions ///////////////// @@ -283,4 +283,4 @@ MenuRegistry.appendMenuItem(MenuId.DataExplorerContext, { title: localize('editData', "Edit Data") }, when: MssqlNodeContext.CanEditData -}); \ No newline at end of file +}); diff --git a/src/sql/workbench/parts/query/browser/query.contribution.ts b/src/sql/workbench/parts/query/browser/query.contribution.ts index ecab30d415..21b5b71b84 100644 --- a/src/sql/workbench/parts/query/browser/query.contribution.ts +++ b/src/sql/workbench/parts/query/browser/query.contribution.ts @@ -80,7 +80,7 @@ if (isMacintosh) { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id: RunQueryKeyboardAction.ID, title: RunQueryKeyboardAction.LABEL }, group: 'query', - when: new ContextKeyEqualsExpr('activeEditor', 'workbench.editor.queryEditor') + when: ContextKeyEqualsExpr.create('activeEditor', 'workbench.editor.queryEditor') }); } diff --git a/src/typings/electron.d.ts b/src/typings/electron.d.ts index c52a879c36..5be0ac0e3f 100644 --- a/src/typings/electron.d.ts +++ b/src/typings/electron.d.ts @@ -1,4 +1,4 @@ -// Type definitions for Electron 4.2.5 +// Type definitions for Electron 4.2.7 // Project: http://electronjs.org/ // Definitions by: The Electron Team // Definitions: https://github.com/electron/electron-typescript-definitions @@ -3479,14 +3479,14 @@ 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. 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. */ static createFromNamedImage(imageName: string, hslShift: number[]): NativeImage; /** @@ -3737,6 +3737,17 @@ declare namespace Electron { once(event: 'unlock-screen', listener: Function): this; addListener(event: 'unlock-screen', listener: Function): this; removeListener(event: 'unlock-screen', listener: Function): this; + /** + * Calculate the system idle state. idleThreshold is the amount of time (in + * seconds) before considered idle. callback will be called synchronously on some + * systems and with an idleState argument that describes the system's state. locked + * is available on supported systems only. + */ + querySystemIdleState(idleThreshold: number, callback: (idleState: 'active' | 'idle' | 'locked' | 'unknown') => void): void; + /** + * Calculate system idle time in seconds. + */ + querySystemIdleTime(callback: (idleTime: number) => void): void; } interface PowerSaveBlocker extends EventEmitter { @@ -4418,30 +4429,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; @@ -8789,17 +8776,33 @@ declare namespace Electron { * The type of media access being requested, can be video, audio or unknown */ mediaType: ('video' | 'audio' | 'unknown'); + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; } interface PermissionRequestHandlerDetails { /** * The url of the openExternal request. */ - externalURL: string; + externalURL?: string; /** * The types of media access being requested, elements can be video or audio */ - mediaTypes: Array<'video' | 'audio'>; + mediaTypes?: Array<'video' | 'audio'>; + /** + * The last URL the requesting frame loaded + */ + requestingUrl: string; + /** + * Whether the frame making the request is the main frame + */ + isMainFrame: boolean; } interface PluginCrashedEvent extends Event { diff --git a/src/typings/xterm.d.ts b/src/typings/xterm.d.ts index 3372f63435..e02926afc7 100644 --- a/src/typings/xterm.d.ts +++ b/src/typings/xterm.d.ts @@ -15,6 +15,11 @@ declare module 'xterm' { */ export type FontWeight = 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; + /** + * A string representing log level. + */ + export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'off'; + /** * A string representing a renderer type. */ @@ -107,6 +112,18 @@ declare module 'xterm' { */ lineHeight?: number; + /** + * What log level to use, this will log for all levels below and including + * what is set: + * + * 1. debug + * 2. info (default) + * 3. warn + * 4. error + * 5. off + */ + logLevel?: LogLevel; + /** * Whether to treat option as the meta key. */ @@ -177,6 +194,12 @@ declare module 'xterm' { * not whitespace. */ windowsMode?: boolean; + + /** + * A string containing all characters that are considered word separated by the + * double click to select work logic. + */ + wordSeparator?: string; } /** @@ -191,7 +214,7 @@ declare module 'xterm' { cursor?: string, /** The accent color of the cursor (fg color for a block cursor) */ cursorAccent?: string, - /** The selection color (can be transparent) */ + /** The selection background color (can be transparent) */ selection?: string, /** ANSI black (eg. `\x1b[30m`) */ black?: string, @@ -483,12 +506,14 @@ declare module 'xterm' { * final character (e.g "m" for SGR) of the CSI sequence. * @param callback The function to handle the escape sequence. The callback * is called with the numerical params, as well as the special characters - * (e.g. "$" for DECSCPP). Return true if the sequence was handled; false if + * (e.g. "$" for DECSCPP). If the sequence has subparams the array will + * contain subarrays with their numercial values. + * Return true if the sequence was handled; false if * we should try a previous handler (set by addCsiHandler or setCsiHandler). * The most recently-added handler is tried first. * @return An IDisposable you can call to remove this handler. */ - addCsiHandler(flag: string, callback: (params: number[], collect: string) => boolean): IDisposable; + addCsiHandler(flag: string, callback: (params: (number | number[])[], collect: string) => boolean): IDisposable; /** * (EXPERIMENTAL) Adds a handler for OSC escape sequences. @@ -668,12 +693,12 @@ declare module 'xterm' { * Retrieves an option's value from the terminal. * @param key The option key. */ - getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'rendererType' | 'termName'): string; + getOption(key: 'bellSound' | 'bellStyle' | 'cursorStyle' | 'fontFamily' | 'fontWeight' | 'fontWeightBold' | 'logLevel' | 'rendererType' | 'termName' | 'wordSeparator'): string; /** * 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' | 'disableStdin' | 'macOptionIsMeta' | 'rightClickSelectsWord' | 'popOnBell' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode'): boolean; /** * Retrieves an option's value from the terminal. * @param key The option key. @@ -700,13 +725,19 @@ declare module 'xterm' { * @param key The option key. * @param value The option value. */ - setOption(key: 'fontFamily' | 'termName' | 'bellSound', value: string): void; + setOption(key: 'fontFamily' | 'termName' | 'bellSound' | 'wordSeparator', value: string): void; /** * Sets an option on the terminal. * @param key The option key. * @param value The option value. */ setOption(key: 'fontWeight' | 'fontWeightBold', value: null | 'normal' | 'bold' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'): void; + /** + * Sets an option on the terminal. + * @param key The option key. + * @param value The option value. + */ + setOption(key: 'logLevel', value: LogLevel): void; /** * Sets an option on the terminal. * @param key The option key. @@ -724,7 +755,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' | 'disableStdin' | 'macOptionIsMeta' | 'popOnBell' | 'rightClickSelectsWord' | 'screenKeys' | 'useFlowControl' | 'visualBell' | 'windowsMode', value: boolean): void; /** * Sets an option on the terminal. * @param key The option key. @@ -928,16 +959,16 @@ declare module 'xterm' { // Modifications to official .d.ts below declare module 'xterm' { interface TerminalCore { - debug: boolean; - - handler(text: string): void; - _onScroll: IEventEmitter; _onKey: IEventEmitter<{ key: string }>; _charSizeService: { width: number; height: number; + }; + + _coreService: { + triggerDataEvent(data: string, wasUserInput?: boolean): void; } _renderService: { diff --git a/src/vs/base/browser/browser.ts b/src/vs/base/browser/browser.ts index 63b7dabf19..c2c111017a 100644 --- a/src/vs/base/browser/browser.ts +++ b/src/vs/base/browser/browser.ts @@ -122,7 +122,7 @@ export const isSafari = (!isChrome && (userAgent.indexOf('Safari') >= 0)); export const isWebkitWebView = (!isChrome && !isSafari && isWebKit); export const isIPad = (userAgent.indexOf('iPad') >= 0); export const isEdgeWebView = isEdge && (userAgent.indexOf('WebView/') >= 0); -export const isStandalone = (window.matchMedia('(display-mode: standalone)').matches); +export const isStandalone = (window.matchMedia && window.matchMedia('(display-mode: standalone)').matches); export function hasClipboardSupport() { if (isIE) { diff --git a/src/vs/base/browser/dom.ts b/src/vs/base/browser/dom.ts index 8d0f3733dd..f9211cfd2a 100644 --- a/src/vs/base/browser/dom.ts +++ b/src/vs/base/browser/dom.ts @@ -1200,7 +1200,7 @@ export function asDomUri(uri: URI): URI { if (Schemas.vscodeRemote === uri.scheme) { // rewrite vscode-remote-uris to uris of the window location // so that they can be intercepted by the service worker - return _location.with({ path: '/vscode-resources/fetch', query: JSON.stringify({ u: uri.toJSON(), i: 1 }) }); + return _location.with({ path: '/vscode-resources/fetch', query: `u=${JSON.stringify(uri)}` }); } return uri; } diff --git a/src/vs/base/browser/mouseEvent.ts b/src/vs/base/browser/mouseEvent.ts index f4040c6300..dcf767b2b1 100644 --- a/src/vs/base/browser/mouseEvent.ts +++ b/src/vs/base/browser/mouseEvent.ts @@ -160,6 +160,8 @@ export class StandardWheelEvent { this.deltaY = e1.wheelDeltaY / 120; } else if (typeof e2.VERTICAL_AXIS !== 'undefined' && e2.axis === e2.VERTICAL_AXIS) { this.deltaY = -e2.detail / 3; + } else { + this.deltaY = -e.deltaY / 40; } // horizontal delta scroll @@ -171,6 +173,8 @@ export class StandardWheelEvent { } } else if (typeof e2.HORIZONTAL_AXIS !== 'undefined' && e2.axis === e2.HORIZONTAL_AXIS) { this.deltaX = -e.detail / 3; + } else { + this.deltaX = -e.deltaX / 40; } // Assume a vertical scroll if nothing else worked @@ -195,4 +199,4 @@ export class StandardWheelEvent { } } } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/centered/centeredViewLayout.ts b/src/vs/base/browser/ui/centered/centeredViewLayout.ts index e25e31fafd..ba51c4c739 100644 --- a/src/vs/base/browser/ui/centered/centeredViewLayout.ts +++ b/src/vs/base/browser/ui/centered/centeredViewLayout.ts @@ -6,7 +6,7 @@ import { SplitView, Orientation, ISplitViewStyles, IView as ISplitViewView } from 'vs/base/browser/ui/splitview/splitview'; import { $ } from 'vs/base/browser/dom'; import { Event } from 'vs/base/common/event'; -import { IView, IViewSize } from 'vs/base/browser/ui/grid/gridview'; +import { IView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; import { Color } from 'vs/base/common/color'; diff --git a/src/vs/base/browser/ui/grid/grid.ts b/src/vs/base/browser/ui/grid/grid.ts index 2d5eb702ba..1d6e2abd1b 100644 --- a/src/vs/base/browser/ui/grid/grid.ts +++ b/src/vs/base/browser/ui/grid/grid.ts @@ -7,10 +7,11 @@ import 'vs/css!./gridview'; import { Orientation } from 'vs/base/browser/ui/sash/sash'; import { Disposable } from 'vs/base/common/lifecycle'; import { tail2 as tail, equals } from 'vs/base/common/arrays'; -import { orthogonal, IView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize } from './gridview'; +import { orthogonal, IView as IGridViewView, GridView, Sizing as GridViewSizing, Box, IGridViewStyles, IViewSize } from './gridview'; import { Event } from 'vs/base/common/event'; +import { InvisibleSizing } from 'vs/base/browser/ui/splitview/splitview'; -export { Orientation, Sizing as GridViewSizing } from './gridview'; +export { Orientation, Sizing as GridViewSizing, IViewSize, orthogonal, LayoutPriority } from './gridview'; export const enum Direction { Up, @@ -28,9 +29,15 @@ function oppositeDirection(direction: Direction): Direction { } } +export interface IView extends IGridViewView { + readonly preferredHeight?: number; + readonly preferredWidth?: number; +} + export interface GridLeafNode { readonly view: T; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -173,16 +180,23 @@ function getGridLocation(element: HTMLElement): number[] { return [...getGridLocation(ancestor), index]; } -export const enum Sizing { - Distribute = 'distribute', - Split = 'split' +export type DistributeSizing = { type: 'distribute' }; +export type SplitSizing = { type: 'split' }; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; + +export namespace Sizing { + export const Distribute: DistributeSizing = { type: 'distribute' }; + export const Split: SplitSizing = { type: 'split' }; + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export interface IGridStyles extends IGridViewStyles { } export interface IGridOptions { - styles?: IGridStyles; - proportionalLayout?: boolean; + readonly styles?: IGridStyles; + readonly proportionalLayout?: boolean; + readonly firstViewVisibleCachedSize?: number; } export class Grid extends Disposable { @@ -208,9 +222,13 @@ export class Grid extends Disposable { this.gridview = new GridView(options); this._register(this.gridview); - this._register(this.gridview.onDidSashReset(this.doResetViewSize, this)); + this._register(this.gridview.onDidSashReset(this.onDidSashReset, this)); - this._addView(view, 0, [0]); + const size: number | GridViewSizing = typeof options.firstViewVisibleCachedSize === 'number' + ? GridViewSizing.Invisible(options.firstViewVisibleCachedSize) + : 0; + + this._addView(view, size, [0]); } style(styles: IGridStyles): void { @@ -241,10 +259,12 @@ export class Grid extends Disposable { let viewSize: number | GridViewSizing; - if (size === Sizing.Split) { + if (typeof size === 'number') { + viewSize = size; + } else if (size.type === 'split') { const [, index] = tail(referenceLocation); viewSize = GridViewSizing.Split(index); - } else if (size === Sizing.Distribute) { + } else if (size.type === 'distribute') { viewSize = GridViewSizing.Distribute; } else { viewSize = size; @@ -264,7 +284,7 @@ export class Grid extends Disposable { } const location = this.getViewLocation(view); - this.gridview.removeView(location, sizing === Sizing.Distribute ? GridViewSizing.Distribute : undefined); + this.gridview.removeView(location, (sizing && sizing.type === 'distribute') ? GridViewSizing.Distribute : undefined); this.views.delete(view); } @@ -320,7 +340,7 @@ export class Grid extends Disposable { } getViews(): GridBranchNode { - return this.gridview.getViews() as GridBranchNode; + return this.gridview.getView() as GridBranchNode; } getNeighborViews(view: T, direction: Direction, wrap: boolean = false): T[] { @@ -355,8 +375,36 @@ export class Grid extends Disposable { return getGridLocation(element); } - private doResetViewSize(location: number[]): void { - const [parentLocation,] = tail(location); + private onDidSashReset(location: number[]): void { + const resizeToPreferredSize = (location: number[]): boolean => { + const node = this.gridview.getView(location) as GridNode; + + if (isGridBranchNode(node)) { + return false; + } + + const direction = getLocationOrientation(this.orientation, location); + const size = direction === Orientation.HORIZONTAL ? node.view.preferredWidth : node.view.preferredHeight; + + if (typeof size !== 'number') { + return false; + } + + const viewSize = direction === Orientation.HORIZONTAL ? { width: Math.round(size) } : { height: Math.round(size) }; + this.gridview.resizeView(location, viewSize); + return true; + }; + + if (resizeToPreferredSize(location)) { + return; + } + + const [parentLocation, index] = tail(location); + + if (resizeToPreferredSize([...parentLocation, index + 1])) { + return; + } + this.gridview.distributeViewSizes(parentLocation); } } @@ -379,6 +427,7 @@ export interface ISerializedLeafNode { type: 'leaf'; data: object | null; size: number; + visible?: boolean; } export interface ISerializedBranchNode { @@ -402,6 +451,10 @@ export class SerializableGrid extends Grid { const size = orientation === Orientation.VERTICAL ? node.box.width : node.box.height; if (!isGridBranchNode(node)) { + if (typeof node.cachedVisibleSize === 'number') { + return { type: 'leaf', data: node.view.toJSON(), size: node.cachedVisibleSize, visible: false }; + } + return { type: 'leaf', data: node.view.toJSON(), size }; } @@ -426,25 +479,26 @@ export class SerializableGrid extends Grid { throw new Error('Invalid JSON: \'size\' property of node must be a number.'); } + const childSize = child.type === 'leaf' && child.visible === false ? 0 : child.size; const childBox: Box = orientation === Orientation.HORIZONTAL - ? { top: box.top, left: box.left + offset, width: child.size, height: box.height } - : { top: box.top + offset, left: box.left, width: box.width, height: child.size }; + ? { top: box.top, left: box.left + offset, width: childSize, height: box.height } + : { top: box.top + offset, left: box.left, width: box.width, height: childSize }; children.push(SerializableGrid.deserializeNode(child, orthogonal(orientation), childBox, deserializer)); - offset += child.size; + offset += childSize; } return { children, box }; } else if (json.type === 'leaf') { const view: T = deserializer.fromJSON(json.data); - return { view, box }; + return { view, box, cachedVisibleSize: json.visible === false ? json.size : undefined }; } throw new Error('Invalid JSON: \'type\' property must be either \'branch\' or \'leaf\'.'); } - private static getFirstLeaf(node: GridNode): GridLeafNode | undefined { + private static getFirstLeaf(node: GridNode): GridLeafNode { if (!isGridBranchNode(node)) { return node; } @@ -473,6 +527,10 @@ export class SerializableGrid extends Grid { throw new Error('Invalid serialized state, first leaf not found'); } + if (typeof firstLeaf.cachedVisibleSize === 'number') { + options = { ...options, firstViewVisibleCachedSize: firstLeaf.cachedVisibleSize }; + } + const result = new SerializableGrid(firstLeaf.view, options); result.orientation = orientation; result.restoreViews(firstLeaf.view, orientation, root); @@ -522,13 +580,16 @@ export class SerializableGrid extends Grid { const firstLeaves = node.children.map(c => SerializableGrid.getFirstLeaf(c)); for (let i = 1; i < firstLeaves.length; i++) { - const size = orientation === Orientation.VERTICAL ? firstLeaves[i]!.box.height : firstLeaves[i]!.box.width; - this.addView(firstLeaves[i]!.view, size, referenceView, direction); - referenceView = firstLeaves[i]!.view; + const node = firstLeaves[i]; + const size: number | InvisibleSizing = typeof node.cachedVisibleSize === 'number' + ? GridViewSizing.Invisible(node.cachedVisibleSize) + : (orientation === Orientation.VERTICAL ? node.box.height : node.box.width); + this.addView(node.view, size, referenceView, direction); + referenceView = node.view; } for (let i = 0; i < node.children.length; i++) { - this.restoreViews(firstLeaves[i]!.view, orthogonal(orientation), node.children[i]); + this.restoreViews(firstLeaves[i].view, orthogonal(orientation), node.children[i]); } } diff --git a/src/vs/base/browser/ui/grid/gridview.ts b/src/vs/base/browser/ui/grid/gridview.ts index fd0abfc651..bbf341b2c3 100644 --- a/src/vs/base/browser/ui/grid/gridview.ts +++ b/src/vs/base/browser/ui/grid/gridview.ts @@ -47,6 +47,7 @@ export interface Box { export interface GridLeafNode { readonly view: IView; readonly box: Box; + readonly cachedVisibleSize: number | undefined; } export interface GridBranchNode { @@ -343,6 +344,14 @@ class BranchNode implements ISplitView, IDisposable { this.splitview.setViewVisible(index, visible); } + getChildCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.children.length) { + throw new Error('Invalid index'); + } + + return this.splitview.getViewCachedVisibleSize(index); + } + private onDidChildrenChange(): void { const onDidChildrenChange = Event.map(Event.any(...this.children.map(c => c.onDidChange)), () => undefined); this.childrenChangeDisposable.dispose(); @@ -424,6 +433,9 @@ class LeafNode implements ISplitView, IDisposable { private _size: number = 0; get size(): number { return this._size; } + private _cachedVisibleSize: number | undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } + private _orthogonalSize: number; get orthogonalSize(): number { return this._orthogonalSize; } @@ -528,6 +540,12 @@ class LeafNode implements ISplitView, IDisposable { } setVisible(visible: boolean): void { + if (visible) { + this._cachedVisibleSize = undefined; + } else { + this._cachedVisibleSize = this._size; + } + if (this.view.setVisible) { this.view.setVisible(visible); } @@ -658,6 +676,14 @@ export class GridView implements IDisposable { } else { const [, grandParent] = tail(pathToParent); const [, parentIndex] = tail(rest); + + let newSiblingSize: number | Sizing = 0; + + const newSiblingCachedVisibleSize = grandParent.getChildCachedVisibleSize(parentIndex); + if (typeof newSiblingCachedVisibleSize === 'number') { + newSiblingSize = Sizing.Invisible(newSiblingCachedVisibleSize); + } + grandParent.removeChild(parentIndex); const newParent = new BranchNode(parent.orientation, this.styles, this.proportionalLayout, parent.size, parent.orthogonalSize); @@ -665,7 +691,7 @@ export class GridView implements IDisposable { newParent.orthogonalLayout(parent.orthogonalSize); const newSibling = new LeafNode(parent.view, grandParent.orientation, parent.size); - newParent.addChild(newSibling, 0, 0); + newParent.addChild(newSibling, newSiblingSize, 0); if (typeof size !== 'number' && size.type === 'split') { size = Sizing.Split(0); @@ -877,13 +903,16 @@ export class GridView implements IDisposable { parent.setChildVisible(index, visible); } - getViews(): GridBranchNode { - return this._getViews(this.root, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }) as GridBranchNode; + getView(): GridBranchNode; + getView(location?: number[]): GridNode; + getView(location?: number[]): GridNode { + const node = location ? this.getNode(location)[1] : this._root; + return this._getViews(node, this.orientation, { top: 0, left: 0, width: this.width, height: this.height }); } private _getViews(node: Node, orientation: Orientation, box: Box): GridNode { if (node instanceof LeafNode) { - return { view: node.view, box }; + return { view: node.view, box, cachedVisibleSize: node.cachedVisibleSize }; } const children: GridNode[] = []; diff --git a/src/vs/base/browser/ui/list/listWidget.ts b/src/vs/base/browser/ui/list/listWidget.ts index 462f115a76..813e7c207d 100644 --- a/src/vs/base/browser/ui/list/listWidget.ts +++ b/src/vs/base/browser/ui/list/listWidget.ts @@ -236,7 +236,7 @@ class KeyboardController implements IDisposable { private view: ListView, options: IListOptions ) { - const multipleSelectionSupport = !(options.multipleSelectionSupport === false); + const multipleSelectionSupport = options.multipleSelectionSupport !== false; this.openController = options.openController || DefaultOpenController; diff --git a/src/vs/base/browser/ui/list/rangeMap.ts b/src/vs/base/browser/ui/list/rangeMap.ts index 11bb1f6aa2..dc1fc0e591 100644 --- a/src/vs/base/browser/ui/list/rangeMap.ts +++ b/src/vs/base/browser/ui/list/rangeMap.ts @@ -190,4 +190,4 @@ export class RangeMap { dispose() { this.groups = null!; // StrictNullOverride: nulling out ok in dispose } -} \ No newline at end of file +} diff --git a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts index 3bdf4ba502..dec154597c 100644 --- a/src/vs/base/browser/ui/scrollbar/scrollableElement.ts +++ b/src/vs/base/browser/ui/scrollbar/scrollableElement.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import 'vs/css!./media/scrollbars'; +import { isEdgeOrIE } from 'vs/base/browser/browser'; import * as dom from 'vs/base/browser/dom'; import { FastDomNode, createFastDomNode } from 'vs/base/browser/fastDomNode'; import { IMouseEvent, StandardWheelEvent, IMouseWheelEvent } from 'vs/base/browser/mouseEvent'; @@ -312,7 +313,7 @@ export abstract class AbstractScrollableElement extends Widget { this._onMouseWheel(new StandardWheelEvent(browserEvent)); }; - this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, 'mousewheel', onMouseWheel)); + this._mouseWheelToDispose.push(dom.addDisposableListener(this._listenOnDomNode, isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel)); } } diff --git a/src/vs/base/browser/ui/splitview/splitview.ts b/src/vs/base/browser/ui/splitview/splitview.ts index b0fb446a2e..bdd519dc66 100644 --- a/src/vs/base/browser/ui/splitview/splitview.ts +++ b/src/vs/base/browser/ui/splitview/splitview.ts @@ -59,8 +59,11 @@ interface ISashEvent { alt: boolean; } +type ViewItemSize = number | { cachedVisibleSize: number }; + abstract class ViewItem { + private _size: number; set size(size: number) { this._size = size; } @@ -69,10 +72,11 @@ abstract class ViewItem { return this._size; } - private cachedSize: number | undefined = undefined; + private _cachedVisibleSize: number | undefined = undefined; + get cachedVisibleSize(): number | undefined { return this._cachedVisibleSize; } get visible(): boolean { - return typeof this.cachedSize === 'undefined'; + return typeof this._cachedVisibleSize === 'undefined'; } set visible(visible: boolean) { @@ -81,10 +85,10 @@ abstract class ViewItem { } if (visible) { - this.size = this.cachedSize!; - this.cachedSize = undefined; + this.size = clamp(this._cachedVisibleSize!, this.viewMinimumSize, this.viewMaximumSize); + this._cachedVisibleSize = undefined; } else { - this.cachedSize = this.size; + this._cachedVisibleSize = this.size; this.size = 0; } @@ -104,7 +108,20 @@ abstract class ViewItem { get priority(): LayoutPriority | undefined { return this.view.priority; } get snap(): boolean { return !!this.view.snap; } - constructor(protected container: HTMLElement, private view: IView, private _size: number, private disposable: IDisposable) { + constructor( + protected container: HTMLElement, + private view: IView, + size: ViewItemSize, + private disposable: IDisposable + ) { + if (typeof size === 'number') { + this._size = size; + this._cachedVisibleSize = undefined; + } else { + this._size = 0; + this._cachedVisibleSize = size.cachedVisibleSize; + } + dom.addClass(container, 'visible'); } @@ -166,11 +183,13 @@ enum State { export type DistributeSizing = { type: 'distribute' }; export type SplitSizing = { type: 'split', index: number }; -export type Sizing = DistributeSizing | SplitSizing; +export type InvisibleSizing = { type: 'invisible', cachedVisibleSize: number }; +export type Sizing = DistributeSizing | SplitSizing | InvisibleSizing; export namespace Sizing { export const Distribute: DistributeSizing = { type: 'distribute' }; export function Split(index: number): SplitSizing { return { type: 'split', index }; } + export function Invisible(cachedVisibleSize: number): InvisibleSizing { return { type: 'invisible', cachedVisibleSize }; } } export class SplitView extends Disposable { @@ -279,12 +298,14 @@ export class SplitView extends Disposable { const containerDisposable = toDisposable(() => this.viewContainer.removeChild(container)); const disposable = combinedDisposable(onChangeDisposable, containerDisposable); - let viewSize: number; + let viewSize: ViewItemSize; if (typeof size === 'number') { viewSize = size; } else if (size.type === 'split') { viewSize = this.getViewSize(size.index) / 2; + } else if (size.type === 'invisible') { + viewSize = { cachedVisibleSize: size.cachedVisibleSize }; } else { viewSize = view.minimumSize; } @@ -315,7 +336,24 @@ export class SplitView extends Disposable { const onChangeDisposable = onChange(this.onSashChange, this); const onEnd = Event.map(sash.onDidEnd, () => firstIndex(this.sashItems, item => item.sash === sash)); const onEndDisposable = onEnd(this.onSashEnd, this); - const onDidResetDisposable = sash.onDidReset(() => this._onDidSashReset.fire(firstIndex(this.sashItems, item => item.sash === sash))); + + const onDidResetDisposable = sash.onDidReset(() => { + const index = firstIndex(this.sashItems, item => item.sash === sash); + const upIndexes = range(index, -1); + const downIndexes = range(index + 1, this.viewItems.length); + const snapBeforeIndex = this.findFirstSnapIndex(upIndexes); + const snapAfterIndex = this.findFirstSnapIndex(downIndexes); + + if (typeof snapBeforeIndex === 'number' && !this.viewItems[snapBeforeIndex].visible) { + return; + } + + if (typeof snapAfterIndex === 'number' && !this.viewItems[snapAfterIndex].visible) { + return; + } + + this._onDidSashReset.fire(index); + }); const disposable = combinedDisposable(onStartDisposable, onChangeDisposable, onEndDisposable, onDidResetDisposable, sash); const sashItem: ISashItem = { sash, disposable }; @@ -420,6 +458,15 @@ export class SplitView extends Disposable { this.layoutViews(); } + getViewCachedVisibleSize(index: number): number | undefined { + if (index < 0 || index >= this.viewItems.length) { + throw new Error('Index out of bounds'); + } + + const viewItem = this.viewItems[index]; + return viewItem.cachedVisibleSize; + } + layout(size: number): void { const previousSize = Math.max(this.size, this.contentSize); this.size = size; @@ -600,10 +647,19 @@ export class SplitView extends Disposable { } distributeViewSizes(): void { - const size = Math.floor(this.size / this.viewItems.length); + const flexibleViewItems: ViewItem[] = []; + let flexibleSize = 0; - for (let i = 0; i < this.viewItems.length; i++) { - const item = this.viewItems[i]; + for (const item of this.viewItems) { + if (item.maximumSize - item.minimumSize > 0) { + flexibleViewItems.push(item); + flexibleSize += item.size; + } + } + + const size = Math.floor(flexibleSize / flexibleViewItems.length); + + for (const item of flexibleViewItems) { item.size = clamp(size, item.minimumSize, item.maximumSize); } diff --git a/src/vs/base/browser/ui/tree/abstractTree.ts b/src/vs/base/browser/ui/tree/abstractTree.ts index 5a2705ad09..e259642cc6 100644 --- a/src/vs/base/browser/ui/tree/abstractTree.ts +++ b/src/vs/base/browser/ui/tree/abstractTree.ts @@ -1183,7 +1183,7 @@ export abstract class AbstractTree implements IDisposable constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private _options: IAbstractTreeOptions = {} ) { const treeDelegate = new ComposedTreeDelegate>(delegate); diff --git a/src/vs/base/browser/ui/tree/asyncDataTree.ts b/src/vs/base/browser/ui/tree/asyncDataTree.ts index 0ff0353db0..2ba29ad9bc 100644 --- a/src/vs/base/browser/ui/tree/asyncDataTree.ts +++ b/src/vs/base/browser/ui/tree/asyncDataTree.ts @@ -320,7 +320,7 @@ export class AsyncDataTree implements IDisposable get onDidFocus(): Event { return this.tree.onDidFocus; } get onDidBlur(): Event { return this.tree.onDidBlur; } - get onDidChangeCollapseState(): Event, TFilterData>> { return this.tree.onDidChangeCollapseState; } + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.tree.onDidChangeCollapseState; } get onDidUpdateOptions(): Event { return this.tree.onDidUpdateOptions; } @@ -340,7 +340,7 @@ export class AsyncDataTree implements IDisposable constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IAsyncDataSource, options: IAsyncDataTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/compressedObjectTree.ts b/src/vs/base/browser/ui/tree/compressedObjectTree.ts new file mode 100644 index 0000000000..c24f666e9d --- /dev/null +++ b/src/vs/base/browser/ui/tree/compressedObjectTree.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 { Iterator, ISequence } from 'vs/base/common/iterator'; +import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; +import { ISpliceable } from 'vs/base/common/sequence'; +import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; +import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; +import { Event } from 'vs/base/common/event'; +import { CompressedTreeModel, ICompressedTreeNode } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; + +export interface IObjectTreeOptions extends IAbstractTreeOptions { + sorter?: ITreeSorter; +} + +export class CompressedObjectTree, TFilterData = void> extends AbstractTree | null, TFilterData, T | null> { + + protected model: CompressedTreeModel; + + get onDidChangeCollapseState(): Event | null, TFilterData>> { return this.model.onDidChangeCollapseState; } + + constructor( + container: HTMLElement, + delegate: IListVirtualDelegate>, + renderers: ITreeRenderer, TFilterData, any>[], + options: IObjectTreeOptions, TFilterData> = {} + ) { + super(container, delegate, renderers, options); + } + + setChildren( + element: T | null, + children?: ISequence> + ): Iterator> { + return this.model.setChildren(element, children); + } + + rerender(element?: T): void { + if (element === undefined) { + this.view.rerender(); + return; + } + + this.model.rerender(element); + } + + resort(element: T, recursive = true): void { + this.model.resort(element, recursive); + } + + protected createModel(view: ISpliceable, TFilterData>>, options: IObjectTreeOptions, TFilterData>): ITreeModel | null, TFilterData, T | null> { + return new CompressedTreeModel(view, options); + } +} diff --git a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts index 5f37a00c30..59dd1a3eed 100644 --- a/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/compressedObjectTreeModel.ts @@ -7,7 +7,7 @@ import { ISpliceable } from 'vs/base/common/sequence'; import { Iterator, ISequence } from 'vs/base/common/iterator'; import { Event } from 'vs/base/common/event'; import { ITreeModel, ITreeNode, ITreeElement, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; -import { IObjectTreeModelOptions, ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; +import { IObjectTreeModelOptions, ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; export interface ICompressedTreeElement extends ITreeElement { readonly children?: Iterator> | ICompressedTreeElement[]; @@ -80,9 +80,9 @@ export function splice(treeElement: ICompressedTreeElement, element: T, ch }; } -export interface ICompressedObjectTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } +export interface ICompressedTreeModelOptions extends IObjectTreeModelOptions, TFilterData> { } -export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { +export class CompressedTreeModel, TFilterData extends NonNullable = void> implements ITreeModel | null, TFilterData, T | null> { readonly rootRef = null; @@ -95,7 +95,7 @@ export class CompressedObjectTreeModel, TFilterData e get size(): number { return this.nodes.size; } - constructor(list: ISpliceable, TFilterData>>, options: ICompressedObjectTreeModelOptions = {}) { + constructor(list: ISpliceable, TFilterData>>, options: ICompressedTreeModelOptions = {}) { this.model = new ObjectTreeModel(list, options); } @@ -289,11 +289,11 @@ function createNodeMapper(elementMapper: ElementMapper): Node return node => mapNode(elementMapper, node); } -export interface ILinearCompressedObjectTreeModelOptions extends ICompressedObjectTreeModelOptions { +export interface ICompressedObjectTreeModelOptions extends ICompressedTreeModelOptions { readonly elementMapper?: ElementMapper; } -export class LinearCompressedObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel { +export class CompressedObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { readonly rootRef = null; @@ -317,15 +317,25 @@ export class LinearCompressedObjectTreeModel, TFilter private mapElement: ElementMapper; private mapNode: NodeMapper; - private model: CompressedObjectTreeModel; + private model: CompressedTreeModel; constructor( list: ISpliceable, TFilterData>>, - options: ILinearCompressedObjectTreeModelOptions = {} + options: ICompressedObjectTreeModelOptions = {} ) { this.mapElement = options.elementMapper || DefaultElementMapper; this.mapNode = createNodeMapper(this.mapElement); - this.model = new CompressedObjectTreeModel(list, options); + this.model = new CompressedTreeModel(list, options); + } + + setChildren( + element: T | null, + children: ISequence> | undefined + ): Iterator> { + this.model.setChildren(element, children); + + // TODO + return Iterator.empty(); } getListIndex(location: T | null): number { @@ -401,4 +411,8 @@ export class LinearCompressedObjectTreeModel, TFilter refilter(): void { return this.model.refilter(); } + + resort(element: T | null = null, recursive = true): void { + return this.model.resort(element, recursive); + } } \ No newline at end of file diff --git a/src/vs/base/browser/ui/tree/dataTree.ts b/src/vs/base/browser/ui/tree/dataTree.ts index 4d6500dc23..4e5cce69d2 100644 --- a/src/vs/base/browser/ui/tree/dataTree.ts +++ b/src/vs/base/browser/ui/tree/dataTree.ts @@ -32,7 +32,7 @@ export class DataTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private dataSource: IDataSource, options: IDataTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/indexTree.ts b/src/vs/base/browser/ui/tree/indexTree.ts index 19c60512fc..b86a170b38 100644 --- a/src/vs/base/browser/ui/tree/indexTree.ts +++ b/src/vs/base/browser/ui/tree/indexTree.ts @@ -20,7 +20,7 @@ export class IndexTree extends AbstractTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], private rootElement: T, options: IIndexTreeOptions = {} ) { diff --git a/src/vs/base/browser/ui/tree/objectTree.ts b/src/vs/base/browser/ui/tree/objectTree.ts index a84399ce5c..04327496ab 100644 --- a/src/vs/base/browser/ui/tree/objectTree.ts +++ b/src/vs/base/browser/ui/tree/objectTree.ts @@ -7,7 +7,7 @@ import { Iterator, ISequence } from 'vs/base/common/iterator'; import { AbstractTree, IAbstractTreeOptions } from 'vs/base/browser/ui/tree/abstractTree'; import { ISpliceable } from 'vs/base/common/sequence'; import { ITreeNode, ITreeModel, ITreeElement, ITreeRenderer, ITreeSorter, ICollapseStateChangeEvent } from 'vs/base/browser/ui/tree/tree'; -import { ObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; +import { ObjectTreeModel, IObjectTreeModel } from 'vs/base/browser/ui/tree/objectTreeModel'; import { IListVirtualDelegate } from 'vs/base/browser/ui/list/list'; import { Event } from 'vs/base/common/event'; @@ -17,14 +17,14 @@ export interface IObjectTreeOptions extends IAbstractTree export class ObjectTree, TFilterData = void> extends AbstractTree { - protected model: ObjectTreeModel; + protected model: IObjectTreeModel; - get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } + get onDidChangeCollapseState(): Event> { return this.model.onDidChangeCollapseState; } constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], options: IObjectTreeOptions = {} ) { super(container, delegate, renderers, options); @@ -32,11 +32,9 @@ export class ObjectTree, TFilterData = void> extends setChildren( element: T | null, - children?: ISequence>, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void + children?: ISequence> ): Iterator> { - return this.model.setChildren(element, children, onDidCreateNode, onDidDeleteNode); + return this.model.setChildren(element, children); } rerender(element?: T): void { diff --git a/src/vs/base/browser/ui/tree/objectTreeModel.ts b/src/vs/base/browser/ui/tree/objectTreeModel.ts index c96bb9ca76..083ff5d2fd 100644 --- a/src/vs/base/browser/ui/tree/objectTreeModel.ts +++ b/src/vs/base/browser/ui/tree/objectTreeModel.ts @@ -10,12 +10,19 @@ import { Event } from 'vs/base/common/event'; import { ITreeModel, ITreeNode, ITreeElement, ITreeSorter, ICollapseStateChangeEvent, ITreeModelSpliceEvent } from 'vs/base/browser/ui/tree/tree'; import { IIdentityProvider } from 'vs/base/browser/ui/list/list'; +export type ITreeNodeCallback = (node: ITreeNode) => void; + +export interface IObjectTreeModel, TFilterData extends NonNullable = void> extends ITreeModel { + setChildren(element: T | null, children: ISequence> | undefined): Iterator>; + resort(element?: T | null, recursive?: boolean): void; +} + export interface IObjectTreeModelOptions extends IIndexTreeModelOptions { readonly sorter?: ITreeSorter; readonly identityProvider?: IIdentityProvider; } -export class ObjectTreeModel, TFilterData extends NonNullable = void> implements ITreeModel { +export class ObjectTreeModel, TFilterData extends NonNullable = void> implements IObjectTreeModel { readonly rootRef = null; @@ -51,8 +58,8 @@ export class ObjectTreeModel, TFilterData extends Non setChildren( element: T | null, children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback ): Iterator> { const location = this.getElementLocation(element); return this._setChildren(location, this.preserveCollapseState(children), onDidCreateNode, onDidDeleteNode); @@ -61,8 +68,8 @@ export class ObjectTreeModel, TFilterData extends Non private _setChildren( location: number[], children: ISequence> | undefined, - onDidCreateNode?: (node: ITreeNode) => void, - onDidDeleteNode?: (node: ITreeNode) => void + onDidCreateNode?: ITreeNodeCallback, + onDidDeleteNode?: ITreeNodeCallback ): Iterator> { const insertedElements = new Set(); const insertedElementIds = new Set(); diff --git a/src/vs/base/common/event.ts b/src/vs/base/common/event.ts index 71f8b84f96..4e9c31737c 100644 --- a/src/vs/base/common/event.ts +++ b/src/vs/base/common/event.ts @@ -326,6 +326,20 @@ export namespace Event { return result.event; } + export interface DOMEventEmitter { + addEventListener(event: string | symbol, listener: Function): void; + removeEventListener(event: string | symbol, listener: Function): void; + } + + export function fromDOMEventEmitter(emitter: DOMEventEmitter, eventName: string, map: (...args: any[]) => T = id => id): Event { + const fn = (...args: any[]) => result.fire(map(...args)); + const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn); + const onLastListenerRemove = () => emitter.removeEventListener(eventName, fn); + const result = new Emitter({ onFirstListenerAdd, onLastListenerRemove }); + + return result.event; + } + export function fromPromise(promise: Promise): Event { const emitter = new Emitter(); let shouldEmit = false; diff --git a/src/vs/base/common/filters.ts b/src/vs/base/common/filters.ts index 75ea7867f2..c728a13721 100644 --- a/src/vs/base/common/filters.ts +++ b/src/vs/base/common/filters.ts @@ -414,7 +414,7 @@ export function createMatches(score: undefined | FuzzyScore): IMatch[] { return res; } -const _maxLen = 53; +const _maxLen = 128; function initTable() { const table: number[][] = []; diff --git a/src/vs/base/common/glob.ts b/src/vs/base/common/glob.ts index 1ee7e3331c..e05fde64d6 100644 --- a/src/vs/base/common/glob.ts +++ b/src/vs/base/common/glob.ts @@ -334,7 +334,6 @@ function wrapRelativePattern(parsedPattern: ParsedStringPattern, arg2: string | if (!extpath.isEqualOrParent(path, arg2.base)) { return null; } - return parsedPattern(paths.relative(arg2.base, path), basename); }; } diff --git a/src/vs/base/common/json.ts b/src/vs/base/common/json.ts index 35a31245fb..779118466b 100644 --- a/src/vs/base/common/json.ts +++ b/src/vs/base/common/json.ts @@ -374,12 +374,12 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON let code = text.charCodeAt(pos); // trivia: whitespace - if (isWhiteSpace(code)) { + if (isWhitespace(code)) { do { pos++; value += String.fromCharCode(code); code = text.charCodeAt(pos); - } while (isWhiteSpace(code)); + } while (isWhitespace(code)); return token = SyntaxKind.Trivia; } @@ -517,7 +517,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON } function isUnknownContentCharacter(code: CharacterCodes) { - if (isWhiteSpace(code) || isLineBreak(code)) { + if (isWhitespace(code) || isLineBreak(code)) { return false; } switch (code) { @@ -555,7 +555,7 @@ export function createScanner(text: string, ignoreTrivia: boolean = false): JSON }; } -function isWhiteSpace(ch: number): boolean { +function isWhitespace(ch: number): boolean { return ch === CharacterCodes.space || ch === CharacterCodes.tab || ch === CharacterCodes.verticalTab || ch === CharacterCodes.formFeed || ch === CharacterCodes.nonBreakingSpace || ch === CharacterCodes.ogham || ch >= CharacterCodes.enQuad && ch <= CharacterCodes.zeroWidthSpace || ch === CharacterCodes.narrowNoBreakSpace || ch === CharacterCodes.mathematicalSpace || ch === CharacterCodes.ideographicSpace || ch === CharacterCodes.byteOrderMark; diff --git a/src/vs/base/test/browser/ui/grid/grid.test.ts b/src/vs/base/test/browser/ui/grid/grid.test.ts deleted file mode 100644 index 07de6510a3..0000000000 --- a/src/vs/base/test/browser/ui/grid/grid.test.ts +++ /dev/null @@ -1,13 +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 assert from 'assert'; - -suite('Grid', function () { - // {{SQL CARBON EDIT}} - test('getRelativeLocation', function () { - assert.equal(0, 0); - }); -}); diff --git a/src/vs/base/test/browser/ui/grid/gridview.test.ts b/src/vs/base/test/browser/ui/grid/gridview.test.ts index 86e246ee35..5e2c505d52 100644 --- a/src/vs/base/test/browser/ui/grid/gridview.test.ts +++ b/src/vs/base/test/browser/ui/grid/gridview.test.ts @@ -22,7 +22,7 @@ suite('Gridview', function () { }); test('empty gridview is empty', function () { - assert.deepEqual(nodesToArrays(gridview.getViews()), []); + assert.deepEqual(nodesToArrays(gridview.getView()), []); gridview.dispose(); }); @@ -43,7 +43,7 @@ suite('Gridview', function () { gridview.addView(views[1], 200, [1]); gridview.addView(views[2], 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -62,7 +62,7 @@ suite('Gridview', function () { gridview.addView((views[1] as TestView[])[0] as IView, 200, [1]); gridview.addView((views[1] as TestView[])[1] as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), views); + assert.deepEqual(nodesToArrays(gridview.getView()), views); gridview.dispose(); }); @@ -71,35 +71,35 @@ suite('Gridview', function () { const view1 = new TestView(20, 20, 20, 20); gridview.addView(view1 as IView, 200, [0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1]); const view2 = new TestView(20, 20, 20, 20); gridview.addView(view2 as IView, 200, [1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, view2]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, view2]); const view3 = new TestView(20, 20, 20, 20); gridview.addView(view3 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view3, view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view3, view2]]); const view4 = new TestView(20, 20, 20, 20); gridview.addView(view4 as IView, 200, [1, 0, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [[view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [[view4, view3], view2]]); const view5 = new TestView(20, 20, 20, 20); gridview.addView(view5 as IView, 200, [1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2]]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2]]); const view6 = new TestView(20, 20, 20, 20); gridview.addView(view6 as IView, 200, [2]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view4, view3], view2], view6]); const view7 = new TestView(20, 20, 20, 20); gridview.addView(view7 as IView, 200, [1, 1]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, view7, [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, view7, [view4, view3], view2], view6]); const view8 = new TestView(20, 20, 20, 20); gridview.addView(view8 as IView, 200, [1, 1, 0]); - assert.deepEqual(nodesToArrays(gridview.getViews()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); + assert.deepEqual(nodesToArrays(gridview.getView()), [view1, [view5, [view8, view7], [view4, view3], view2], view6]); gridview.dispose(); }); diff --git a/src/vs/base/test/browser/ui/grid/util.ts b/src/vs/base/test/browser/ui/grid/util.ts index 15da109dcd..7e167c8eeb 100644 --- a/src/vs/base/test/browser/ui/grid/util.ts +++ b/src/vs/base/test/browser/ui/grid/util.ts @@ -5,7 +5,8 @@ import * as assert from 'assert'; import { Emitter, Event } from 'vs/base/common/event'; -import { IView, GridNode, isGridBranchNode, } from 'vs/base/browser/ui/grid/gridview'; +import { GridNode, isGridBranchNode } from 'vs/base/browser/ui/grid/gridview'; +import { IView } from 'vs/base/browser/ui/grid/grid'; export class TestView implements IView { @@ -78,4 +79,4 @@ export function nodesToArrays(node: GridNode): any { } else { return node.view; } -} \ No newline at end of file +} diff --git a/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts index 34cbe612a9..d1d6c9a68b 100644 --- a/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts +++ b/src/vs/base/test/browser/ui/tree/compressedObjectTreeModel.test.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import * as assert from 'assert'; -import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedObjectTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; +import { compress, ICompressedTreeElement, ICompressedTreeNode, decompress, CompressedTreeModel } from 'vs/base/browser/ui/tree/compressedObjectTreeModel'; import { Iterator } from 'vs/base/common/iterator'; import { ITreeNode } from 'vs/base/browser/ui/tree/tree'; import { ISpliceable } from 'vs/base/common/sequence'; @@ -305,7 +305,7 @@ suite('CompressedObjectTree', function () { test('ctor', () => { const list: ITreeNode>[] = []; - const model = new CompressedObjectTreeModel(toSpliceable(list)); + const model = new CompressedTreeModel(toSpliceable(list)); assert(model); assert.equal(list.length, 0); assert.equal(model.size, 0); @@ -313,7 +313,7 @@ suite('CompressedObjectTree', function () { test('flat', () => { const list: ITreeNode>[] = []; - const model = new CompressedObjectTreeModel(toSpliceable(list)); + const model = new CompressedTreeModel(toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { element: 0 }, @@ -340,7 +340,7 @@ suite('CompressedObjectTree', function () { test('nested', () => { const list: ITreeNode>[] = []; - const model = new CompressedObjectTreeModel(toSpliceable(list)); + const model = new CompressedTreeModel(toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { @@ -376,7 +376,7 @@ suite('CompressedObjectTree', function () { test('compressed', () => { const list: ITreeNode>[] = []; - const model = new CompressedObjectTreeModel(toSpliceable(list)); + const model = new CompressedTreeModel(toSpliceable(list)); model.setChildren(null, Iterator.fromArray([ { diff --git a/src/vs/base/test/common/filters.test.ts b/src/vs/base/test/common/filters.test.ts index 33cff513b1..129ba8c39e 100644 --- a/src/vs/base/test/common/filters.test.ts +++ b/src/vs/base/test/common/filters.test.ts @@ -470,4 +470,19 @@ suite('Filters', () => { test('List highlight filter: Not all characters from match are highlighterd #66923', () => { assertMatches('foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', 'barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', fuzzyScore); }); + + test('Autocompletion is matched against truncated filterText to 54 characters #74133', () => { + assertMatches( + 'foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + 'ffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_^f^o^o', + fuzzyScore + ); + assertMatches( + 'foo', + 'Gffffffffffffffffffffffffffffbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar_foo', + undefined, + fuzzyScore + ); + }); }); diff --git a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts index d6e3e908ec..0a2b94413f 100644 --- a/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts +++ b/src/vs/code/electron-browser/sharedProcess/sharedProcessMain.ts @@ -37,7 +37,7 @@ import { ILocalizationsService } from 'vs/platform/localizations/common/localiza import { LocalizationsChannel } from 'vs/platform/localizations/node/localizationsIpc'; import { DialogChannelClient } from 'vs/platform/dialogs/node/dialogIpc'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; -import { combinedDisposable, DisposableStore } from 'vs/base/common/lifecycle'; +import { combinedDisposable, DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; import { DownloadService } from 'vs/platform/download/common/downloadService'; import { IDownloadService } from 'vs/platform/download/common/download'; import { IChannel, IServerChannel, StaticRouter } from 'vs/base/parts/ipc/common/ipc'; @@ -154,7 +154,7 @@ async function main(server: Server, initData: ISharedProcessInitData, configurat if (!extensionDevelopmentLocationURI && !environmentService.args['disable-telemetry'] && product.enableTelemetry) { if (product.aiConfig && product.aiConfig.asimovKey && isBuilt) { appInsightsAppender = new AppInsightsAppender(eventPrefix, null, product.aiConfig.asimovKey, telemetryLogService); - disposables.add(appInsightsAppender); // Ensure the AI appender is disposed so that it flushes remaining data + disposables.add(toDisposable(() => appInsightsAppender!.flush())); // Ensure the AI appender is disposed so that it flushes remaining data } const config: ITelemetryServiceConfig = { appender: combinedAppender(appInsightsAppender, new LogAppender(logService)), diff --git a/src/vs/code/electron-main/app.ts b/src/vs/code/electron-main/app.ts index 5628e42dc8..133fe903b5 100644 --- a/src/vs/code/electron-main/app.ts +++ b/src/vs/code/electron-main/app.ts @@ -77,7 +77,7 @@ import { HistoryMainService } from 'vs/platform/history/electron-main/historyMai import { URLService } from 'vs/platform/url/common/urlService'; import { WorkspacesMainService } from 'vs/platform/workspaces/electron-main/workspacesMainService'; import { RemoteAgentConnectionContext } from 'vs/platform/remote/common/remoteAgentEnvironment'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { VSBuffer } from 'vs/base/common/buffer'; import { statSync } from 'fs'; import { ISignService } from 'vs/platform/sign/common/sign'; @@ -167,9 +167,11 @@ export class CodeApplication extends Disposable { event.preventDefault(); }); app.on('remote-get-current-web-contents', event => { - this.logService.trace(`App#on(remote-get-current-web-contents): prevented`); - - event.preventDefault(); + // The driver needs access to web contents + if (!this.environmentService.args.driver) { + this.logService.trace(`App#on(remote-get-current-web-contents): prevented`); + event.preventDefault(); + } }); app.on('web-contents-created', (_event: Electron.Event, contents) => { contents.on('will-attach-webview', (event: Electron.Event, webPreferences, params) => { @@ -708,7 +710,7 @@ export class CodeApplication extends Disposable { const options: IConnectionOptions = { isBuilt, commit: product.commit, - webSocketFactory: nodeWebSocketFactory, + socketFactory: nodeSocketFactory, addressProvider: { getAddress: () => { return Promise.resolve({ host, port }); diff --git a/src/vs/code/node/cliProcessMain.ts b/src/vs/code/node/cliProcessMain.ts index 0ef2e21193..164db194d5 100644 --- a/src/vs/code/node/cliProcessMain.ts +++ b/src/vs/code/node/cliProcessMain.ts @@ -86,7 +86,7 @@ export class Main { await this.setInstallSource(argv['install-source']); } else if (argv['list-extensions']) { - await this.listExtensions(!!argv['show-versions']); + await this.listExtensions(!!argv['show-versions'], argv['category']); } else if (argv['install-extension']) { const arg = argv['install-extension']; @@ -110,8 +110,17 @@ export class Main { return writeFile(this.environmentService.installSourcePath, installSource.slice(0, 30)); } - private async listExtensions(showVersions: boolean): Promise { - const extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + private async listExtensions(showVersions: boolean, category?: string): Promise { + let extensions = await this.extensionManagementService.getInstalled(ExtensionType.User); + if (category) { + extensions = extensions.filter(e => { + if (e.manifest.categories) { + const lowerCaseCategories: string[] = e.manifest.categories.map(c => c.toLowerCase()); + return lowerCaseCategories.indexOf(category.toLowerCase()) > -1; + } + return false; + }); + } extensions.forEach(e => console.log(getId(e.manifest, showVersions))); } @@ -345,8 +354,6 @@ export async function main(argv: ParsedArgs): Promise { services.set(ITelemetryService, new SyncDescriptor(TelemetryService, [config])); - // Dispose the AI adapter so that remaining data gets flushed. - disposables.add(combinedAppender(...appenders)); } else { services.set(ITelemetryService, NullTelemetryService); } @@ -356,6 +363,8 @@ export async function main(argv: ParsedArgs): Promise { try { await main.run(argv); + // Flush the remaining data in AI adapter. + await combinedAppender(...appenders).flush(); } finally { disposables.dispose(); } diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index 480440d5c3..7871f66421 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -123,7 +123,7 @@ export class MouseHandler extends ViewEventHandler { e.stopPropagation(); } }; - this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, 'mousewheel', onMouseWheel, true)); + this._register(dom.addDisposableListener(this.viewHelper.viewDomNode, browser.isEdgeOrIE ? 'mousewheel' : 'wheel', onMouseWheel, true)); this._context.addEventHandler(this); } diff --git a/src/vs/editor/browser/controller/mouseTarget.ts b/src/vs/editor/browser/controller/mouseTarget.ts index 84316ef4e1..0baf78d1ad 100644 --- a/src/vs/editor/browser/controller/mouseTarget.ts +++ b/src/vs/editor/browser/controller/mouseTarget.ts @@ -407,7 +407,12 @@ class HitTestRequest extends BareHitTestRequest { } public fulfill(type: MouseTargetType, position: Position | null = null, range: EditorRange | null = null, detail: any = null): MouseTarget { - return new MouseTarget(this.target, type, this.mouseColumn, position, range, detail); + let mouseColumn = this.mouseColumn; + if (position && position.column < this._ctx.model.getLineMaxColumn(position.lineNumber)) { + // Most likely, the line contains foreign decorations... + mouseColumn = position.column; + } + return new MouseTarget(this.target, type, mouseColumn, position, range, detail); } public withTarget(target: Element | null): HitTestRequest { diff --git a/src/vs/editor/browser/editorExtensions.ts b/src/vs/editor/browser/editorExtensions.ts index ab0c4717e6..3dadbaedfd 100644 --- a/src/vs/editor/browser/editorExtensions.ts +++ b/src/vs/editor/browser/editorExtensions.ts @@ -24,6 +24,10 @@ import { withNullAsUndefined } from 'vs/base/common/types'; export type ServicesAccessor = ServicesAccessor; export type IEditorContributionCtor = IConstructorSignature1; +export type EditorTelemetryDataFragment = { + target: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + snippet: { classification: 'SystemMetaData', purpose: 'FeatureInsight', isMeasurement: true }; +}; //#region Command @@ -219,16 +223,15 @@ export abstract class EditorAction extends EditorCommand { } protected reportTelemetry(accessor: ServicesAccessor, editor: ICodeEditor) { - /* __GDPR__ - "editorActionInvoked" : { - "name" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "id": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "${include}": [ - "${EditorTelemetryData}" - ] - } - */ - accessor.get(ITelemetryService).publicLog('editorActionInvoked', { name: this.label, id: this.id, ...editor.getTelemetryData() }); + type EditorActionInvokedClassification = { + name: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + id: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + type EditorActionInvokedEvent = { + name: string; + id: string; + }; + accessor.get(ITelemetryService).publicLog2('editorActionInvoked', { name: this.label, id: this.id }); } public abstract run(accessor: ServicesAccessor, editor: ICodeEditor, args: any): void | Promise; diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 3e5f73e511..0223a9b2ec 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -1508,9 +1508,6 @@ export class CodeEditorWidget extends Disposable implements editorBrowser.ICodeE return this._codeEditorService.resolveDecorationOptions(typeKey, writable); } - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : {} - */ public getTelemetryData(): { [key: string]: any; } | undefined { return this._telemetryData; } @@ -1851,4 +1848,6 @@ registerThemingParticipant((theme, collector) => { if (unnecessaryBorder) { collector.addRule(`.${SHOW_UNUSED_ENABLED_CLASS} .monaco-editor .${ClassName.EditorUnnecessaryDecoration} { border-bottom: 2px dashed ${unnecessaryBorder}; }`); } + + collector.addRule(`.monaco-editor .${ClassName.EditorDeprecatedInlineDecoration} { text-decoration: line-through; }`); }); diff --git a/src/vs/editor/browser/widget/media/editor.css b/src/vs/editor/browser/widget/media/editor.css index a3eb23e495..433b84bf39 100644 --- a/src/vs/editor/browser/widget/media/editor.css +++ b/src/vs/editor/browser/widget/media/editor.css @@ -39,4 +39,10 @@ .monaco-editor .view-overlays { position: absolute; top: 0; -} \ No newline at end of file +} + +/* +.monaco-editor .auto-closed-character { + opacity: 0.3; +} +*/ diff --git a/src/vs/editor/common/config/commonEditorConfig.ts b/src/vs/editor/common/config/commonEditorConfig.ts index 56cfb4e99e..a8daa9c55c 100644 --- a/src/vs/editor/common/config/commonEditorConfig.ts +++ b/src/vs/editor/common/config/commonEditorConfig.ts @@ -696,7 +696,7 @@ const editorConfiguration: IConfigurationNode = { }, 'editor.suggest.filteredTypes': { type: 'object', - default: { keyword: true }, + default: { keyword: true, snippet: true }, markdownDescription: nls.localize('suggest.filtered', "Controls whether some suggestion types should be filtered from IntelliSense. A list of suggestion types can be found here: https://code.visualstudio.com/docs/editor/intellisense#_types-of-completions."), properties: { method: { @@ -904,7 +904,7 @@ const editorConfiguration: IConfigurationNode = { 'enum': ['none', 'boundary', 'selection', 'all'], 'enumDescriptions': [ '', - nls.localize('renderWhiteSpace.boundary', "Render whitespace characters except for single spaces between words."), + nls.localize('renderWhitespace.boundary', "Render whitespace characters except for single spaces between words."), nls.localize('renderWhitespace.selection', "Render whitespace characters only on selected text."), '' ], diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index 7f2a5863e9..9c38bac730 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -10,15 +10,16 @@ import { CursorCollection } from 'vs/editor/common/controller/cursorCollection'; import { CursorColumns, CursorConfiguration, CursorContext, CursorState, EditOperationResult, EditOperationType, IColumnSelectData, ICursors, PartialCursorState, RevealTarget } from 'vs/editor/common/controller/cursorCommon'; import { DeleteOperations } from 'vs/editor/common/controller/cursorDeleteOperations'; import { CursorChangeReason } from 'vs/editor/common/controller/cursorEvents'; -import { TypeOperations } from 'vs/editor/common/controller/cursorTypeOperations'; +import { TypeOperations, TypeWithAutoClosingCommand } from 'vs/editor/common/controller/cursorTypeOperations'; import { Position } from 'vs/editor/common/core/position'; import { Range } from 'vs/editor/common/core/range'; import { ISelection, Selection, SelectionDirection } from 'vs/editor/common/core/selection'; import * as editorCommon from 'vs/editor/common/editorCommon'; -import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness } from 'vs/editor/common/model'; +import { IIdentifiedSingleEditOperation, ITextModel, TrackedRangeStickiness, IModelDeltaDecoration } from 'vs/editor/common/model'; import { RawContentChangedType } from 'vs/editor/common/model/textModelEvents'; import * as viewEvents from 'vs/editor/common/view/viewEvents'; import { IViewModel } from 'vs/editor/common/viewModel/viewModel'; +import { dispose } from 'vs/base/common/lifecycle'; function containsLineMappingChanged(events: viewEvents.ViewEvent[]): boolean { for (let i = 0, len = events.length; i < len; i++) { @@ -83,6 +84,64 @@ export class CursorModelState { } } +class AutoClosedAction { + + private readonly _model: ITextModel; + + private _autoClosedCharactersDecorations: string[]; + private _autoClosedEnclosingDecorations: string[]; + + constructor(model: ITextModel, autoClosedCharactersDecorations: string[], autoClosedEnclosingDecorations: string[]) { + this._model = model; + this._autoClosedCharactersDecorations = autoClosedCharactersDecorations; + this._autoClosedEnclosingDecorations = autoClosedEnclosingDecorations; + } + + public dispose(): void { + this._autoClosedCharactersDecorations = this._model.deltaDecorations(this._autoClosedCharactersDecorations, []); + this._autoClosedEnclosingDecorations = this._model.deltaDecorations(this._autoClosedEnclosingDecorations, []); + } + + public getAutoClosedCharactersRanges(): Range[] { + let result: Range[] = []; + for (let i = 0; i < this._autoClosedCharactersDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedCharactersDecorations[i]); + if (decorationRange) { + result.push(decorationRange); + } + } + return result; + } + + public isValid(selections: Range[]): boolean { + let enclosingRanges: Range[] = []; + for (let i = 0; i < this._autoClosedEnclosingDecorations.length; i++) { + const decorationRange = this._model.getDecorationRange(this._autoClosedEnclosingDecorations[i]); + if (decorationRange) { + enclosingRanges.push(decorationRange); + if (decorationRange.startLineNumber !== decorationRange.endLineNumber) { + // Stop tracking if the range becomes multiline... + return false; + } + } + } + enclosingRanges.sort(Range.compareRangesUsingStarts); + + selections.sort(Range.compareRangesUsingStarts); + + for (let i = 0; i < selections.length; i++) { + if (i >= enclosingRanges.length) { + return false; + } + if (!enclosingRanges[i].strictContainsRange(selections[i])) { + return false; + } + } + + return true; + } +} + export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public static MAX_CURSOR_COUNT = 10000; @@ -106,6 +165,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { private _isHandling: boolean; private _isDoingComposition: boolean; private _columnSelectData: IColumnSelectData | null; + private _autoClosedActions: AutoClosedAction[]; private _prevEditOperationType: EditOperationType; constructor(configuration: editorCommon.IConfiguration, model: ITextModel, viewModel: IViewModel) { @@ -120,6 +180,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._isHandling = false; this._isDoingComposition = false; this._columnSelectData = null; + this._autoClosedActions = []; this._prevEditOperationType = EditOperationType.Other; this._register(this._model.onDidChangeRawContent((e) => { @@ -173,9 +234,24 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { public dispose(): void { this._cursors.dispose(); + this._autoClosedActions = dispose(this._autoClosedActions); super.dispose(); } + private _validateAutoClosedActions(): void { + if (this._autoClosedActions.length > 0) { + let selections: Range[] = this._cursors.getSelections(); + for (let i = 0; i < this._autoClosedActions.length; i++) { + const autoClosedAction = this._autoClosedActions[i]; + if (!autoClosedAction.isValid(selections)) { + autoClosedAction.dispose(); + this._autoClosedActions.splice(i, 1); + i--; + } + } + } + } + // ------ some getters/setters public getPrimaryCursor(): CursorState { @@ -202,6 +278,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.normalize(); this._columnSelectData = null; + this._validateAutoClosedActions(); + this._emitStateChangedIfNecessary(source, reason, oldState); } @@ -296,7 +374,7 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // a model.setValue() was called this._cursors.dispose(); this._cursors = new CursorCollection(this.context); - + this._validateAutoClosedActions(); this._emitStateChangedIfNecessary('model', CursorChangeReason.ContentFlush, null); } else { const selectionsFromMarkers = this._cursors.readSelectionFromMarkers(); @@ -367,6 +445,35 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { // The commands were applied correctly this._interpretCommandResult(result); + // Check for auto-closing closed characters + let autoClosedCharactersRanges: IModelDeltaDecoration[] = []; + let autoClosedEnclosingRanges: IModelDeltaDecoration[] = []; + + for (let i = 0; i < opResult.commands.length; i++) { + const command = opResult.commands[i]; + if (command instanceof TypeWithAutoClosingCommand && command.enclosingRange && command.closeCharacterRange) { + autoClosedCharactersRanges.push({ + range: command.closeCharacterRange, + options: { + inlineClassName: 'auto-closed-character', + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + autoClosedEnclosingRanges.push({ + range: command.enclosingRange, + options: { + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges + } + }); + } + } + + if (autoClosedCharactersRanges.length > 0) { + const autoClosedCharactersDecorations = this._model.deltaDecorations([], autoClosedCharactersRanges); + const autoClosedEnclosingDecorations = this._model.deltaDecorations([], autoClosedEnclosingRanges); + this._autoClosedActions.push(new AutoClosedAction(this._model, autoClosedCharactersDecorations, autoClosedEnclosingDecorations)); + } + this._prevEditOperationType = opResult.type; } @@ -540,6 +647,8 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { this._cursors.startTrackingSelections(); } + this._validateAutoClosedActions(); + if (this._emitStateChangedIfNecessary(source, cursorChangeReason, oldState)) { this._revealRange(RevealTarget.Primary, viewEvents.VerticalRevealType.Simple, true, editorCommon.ScrollType.Smooth); } @@ -566,8 +675,15 @@ export class Cursor extends viewEvents.ViewEventEmitter implements ICursors { chr = text.charAt(i); } + let autoClosedCharacters: Range[] = []; + if (this._autoClosedActions.length > 0) { + for (let i = 0, len = this._autoClosedActions.length; i < len; i++) { + autoClosedCharacters = autoClosedCharacters.concat(this._autoClosedActions[i].getAutoClosedCharactersRanges()); + } + } + // Here we must interpret each typed character individually, that's why we create a new context - this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), chr)); + this._executeEditOperation(TypeOperations.typeWithInterceptors(this._prevEditOperationType, this.context.config, this.context.model, this.getSelections(), autoClosedCharacters, chr)); } } else { diff --git a/src/vs/editor/common/controller/cursorTypeOperations.ts b/src/vs/editor/common/controller/cursorTypeOperations.ts index 4424c42c2d..430e227942 100644 --- a/src/vs/editor/common/controller/cursorTypeOperations.ts +++ b/src/vs/editor/common/controller/cursorTypeOperations.ts @@ -13,7 +13,7 @@ import { CursorColumns, CursorConfiguration, EditOperationResult, EditOperationT import { WordCharacterClass, getMapForWordSeparators } from 'vs/editor/common/controller/wordCharacterClassifier'; import { Range } from 'vs/editor/common/core/range'; import { Selection } from 'vs/editor/common/core/selection'; -import { ICommand } from 'vs/editor/common/editorCommon'; +import { ICommand, ICursorStateComputerData } from 'vs/editor/common/editorCommon'; import { ITextModel } from 'vs/editor/common/model'; import { EnterAction, IndentAction } from 'vs/editor/common/modes/languageConfiguration'; import { LanguageConfigurationRegistry } from 'vs/editor/common/modes/languageConfigurationRegistry'; @@ -430,7 +430,7 @@ export class TypeOperations { return null; } - private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): boolean { + private static _isAutoClosingCloseCharType(config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): boolean { const autoCloseConfig = isQuote(ch) ? config.autoClosingQuotes : config.autoClosingBrackets; if (autoCloseConfig === 'never' || !config.autoClosingPairsClose.hasOwnProperty(ch)) { @@ -461,6 +461,19 @@ export class TypeOperations { return false; } } + + // Must over-type a closing character typed by the editor + let found = false; + for (let j = 0, lenJ = autoClosedCharacters.length; j < lenJ; j++) { + const autoClosedCharacter = autoClosedCharacters[j]; + if (position.lineNumber === autoClosedCharacter.startLineNumber && position.column === autoClosedCharacter.startColumn) { + found = true; + break; + } + } + if (!found) { + return false; + } } return true; @@ -573,7 +586,7 @@ export class TypeOperations { for (let i = 0, len = selections.length; i < len; i++) { const selection = selections[i]; const closeCharacter = config.autoClosingPairsOpen[ch]; - commands[i] = new ReplaceCommandWithOffsetCursorState(selection, ch + closeCharacter, 0, -closeCharacter.length); + commands[i] = new TypeWithAutoClosingCommand(selection, ch, closeCharacter); } return new EditOperationResult(EditOperationType.Typing, commands, { shouldPushStackElementBefore: true, @@ -802,7 +815,7 @@ export class TypeOperations { }); } - public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], ch: string): EditOperationResult { + public static typeWithInterceptors(prevEditOperationType: EditOperationType, config: CursorConfiguration, model: ITextModel, selections: Selection[], autoClosedCharacters: Range[], ch: string): EditOperationResult { if (ch === '\n') { let commands: ICommand[] = []; @@ -833,7 +846,7 @@ export class TypeOperations { } } - if (this._isAutoClosingCloseCharType(config, model, selections, ch)) { + if (this._isAutoClosingCloseCharType(config, model, selections, autoClosedCharacters, ch)) { return this._runAutoClosingCloseCharType(prevEditOperationType, config, model, selections, ch); } @@ -923,3 +936,24 @@ export class TypeOperations { return commands; } } + +export class TypeWithAutoClosingCommand extends ReplaceCommandWithOffsetCursorState { + + private _closeCharacter: string; + public closeCharacterRange: Range | null; + public enclosingRange: Range | null; + + constructor(selection: Selection, openCharacter: string, closeCharacter: string) { + super(selection, openCharacter + closeCharacter, 0, -closeCharacter.length); + this._closeCharacter = closeCharacter; + this.closeCharacterRange = null; + } + + public computeCursorState(model: ITextModel, helper: ICursorStateComputerData): Selection { + let inverseEditOperations = helper.getInverseEditOperations(); + let range = inverseEditOperations[0].range; + this.closeCharacterRange = new Range(range.startLineNumber, range.endColumn - this._closeCharacter.length, range.endLineNumber, range.endColumn); + this.enclosingRange = range; + return super.computeCursorState(model, helper); + } +} diff --git a/src/vs/editor/common/core/range.ts b/src/vs/editor/common/core/range.ts index 584b68b6d4..fb5cbd813c 100644 --- a/src/vs/editor/common/core/range.ts +++ b/src/vs/editor/common/core/range.ts @@ -126,6 +126,32 @@ export class Range { return true; } + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + public strictContainsRange(range: IRange): boolean { + return Range.strictContainsRange(this, range); + } + + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + public static strictContainsRange(range: IRange, otherRange: IRange): boolean { + if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { + return false; + } + if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { + return false; + } + if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { + return false; + } + if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { + return false; + } + return true; + } + /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. diff --git a/src/vs/editor/common/model/intervalTree.ts b/src/vs/editor/common/model/intervalTree.ts index 54f5ea91d2..00154b16aa 100644 --- a/src/vs/editor/common/model/intervalTree.ts +++ b/src/vs/editor/common/model/intervalTree.ts @@ -17,7 +17,8 @@ export const enum ClassName { EditorWarningDecoration = 'squiggly-warning', EditorErrorDecoration = 'squiggly-error', EditorUnnecessaryDecoration = 'squiggly-unnecessary', - EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary' + EditorUnnecessaryInlineDecoration = 'squiggly-inline-unnecessary', + EditorDeprecatedInlineDecoration = 'squiggly-inline-deprecated' } export const enum NodeColor { diff --git a/src/vs/editor/common/model/textModelSearch.ts b/src/vs/editor/common/model/textModelSearch.ts index 287418ec63..e2ebdf719d 100644 --- a/src/vs/editor/common/model/textModelSearch.ts +++ b/src/vs/editor/common/model/textModelSearch.ts @@ -545,6 +545,12 @@ export class Searcher { const matchStartIndex = m.index; const matchLength = m[0].length; if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) { + if (matchLength === 0) { + // the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here + // we attempt to recover from that by advancing by one + this._searchRegex.lastIndex += 1; + continue; + } // Exit early if the regex matches the same range twice return null; } diff --git a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts index 4710c947f0..3c040747c4 100644 --- a/src/vs/editor/common/services/markerDecorationsServiceImpl.ts +++ b/src/vs/editor/common/services/markerDecorationsServiceImpl.ts @@ -221,6 +221,9 @@ export class MarkerDecorationsService extends Disposable implements IMarkerDecor if (marker.tags.indexOf(MarkerTag.Unnecessary) !== -1) { inlineClassName = ClassName.EditorUnnecessaryInlineDecoration; } + if (marker.tags.indexOf(MarkerTag.Deprecated) !== -1) { + inlineClassName = ClassName.EditorDeprecatedInlineDecoration; + } } return { diff --git a/src/vs/editor/common/standalone/standaloneEnums.ts b/src/vs/editor/common/standalone/standaloneEnums.ts index ce5fe1e1a4..d2864eb9a1 100644 --- a/src/vs/editor/common/standalone/standaloneEnums.ts +++ b/src/vs/editor/common/standalone/standaloneEnums.ts @@ -7,7 +7,8 @@ export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/editor/contrib/clipboard/clipboard.ts b/src/vs/editor/contrib/clipboard/clipboard.ts index f736226271..b047f1b05e 100644 --- a/src/vs/editor/contrib/clipboard/clipboard.ts +++ b/src/vs/editor/contrib/clipboard/clipboard.ts @@ -148,12 +148,6 @@ class ExecCommandCopyAction extends ExecCommandAction { if (!emptySelectionClipboard && editor.getSelection().isEmpty()) { return; } - // Prevent copying an empty line by accident - if (editor.getSelections().length === 1 && editor.getSelection().isEmpty()) { - if (editor.getModel().getLineFirstNonWhitespaceColumn(editor.getSelection().positionLineNumber) === 0) { - return; - } - } super.run(accessor, editor); } diff --git a/src/vs/editor/contrib/documentSymbols/outlineTree.ts b/src/vs/editor/contrib/documentSymbols/outlineTree.ts index 7faebde985..cdc98bf098 100644 --- a/src/vs/editor/contrib/documentSymbols/outlineTree.ts +++ b/src/vs/editor/contrib/documentSymbols/outlineTree.ts @@ -13,7 +13,7 @@ import 'vs/css!./media/outlineTree'; import 'vs/css!./media/symbol-icons'; import { Range } from 'vs/editor/common/core/range'; import { SymbolKind, symbolKindToCssClass } from 'vs/editor/common/modes'; -import { OutlineElement, OutlineGroup, OutlineModel, TreeElement } from 'vs/editor/contrib/documentSymbols/outlineModel'; +import { OutlineElement, OutlineGroup, OutlineModel } from 'vs/editor/contrib/documentSymbols/outlineModel'; import { localize } from 'vs/nls'; import { IconLabel } from 'vs/base/browser/ui/iconLabel/iconLabel'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; @@ -38,7 +38,7 @@ export class OutlineNavigationLabelProvider implements IKeyboardNavigationLabelP export class OutlineIdentityProvider implements IIdentityProvider { - getId(element: TreeElement): { toString(): string; } { + getId(element: OutlineItem): { toString(): string; } { return element.id; } } diff --git a/src/vs/editor/contrib/find/findController.ts b/src/vs/editor/contrib/find/findController.ts index 0b8cad0358..e5c7058385 100644 --- a/src/vs/editor/contrib/find/findController.ts +++ b/src/vs/editor/contrib/find/findController.ts @@ -112,7 +112,8 @@ export class CommonFindController extends Disposable implements editorCommon.IEd searchScope: null, matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, false), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, false), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, false), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, false) }, false); if (shouldRestartFind) { @@ -170,13 +171,17 @@ export class CommonFindController extends Disposable implements editorCommon.IEd if (e.matchCase) { this._storageService.store('editor.matchCase', this._state.actualMatchCase, StorageScope.WORKSPACE); } + if (e.preserveCase) { + this._storageService.store('editor.preserveCase', this._state.actualPreserveCase, StorageScope.WORKSPACE); + } } private loadQueryState() { this._state.change({ matchCase: this._storageService.getBoolean('editor.matchCase', StorageScope.WORKSPACE, this._state.matchCase), wholeWord: this._storageService.getBoolean('editor.wholeWord', StorageScope.WORKSPACE, this._state.wholeWord), - isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex) + isRegex: this._storageService.getBoolean('editor.isRegex', StorageScope.WORKSPACE, this._state.isRegex), + preserveCase: this._storageService.getBoolean('editor.preserveCase', StorageScope.WORKSPACE, this._state.preserveCase) }, false); } @@ -217,6 +222,11 @@ export class CommonFindController extends Disposable implements editorCommon.IEd } } + public togglePreserveCase(): void { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this.highlightFindOptions(); + } + public toggleSearchScope(): void { if (this._state.searchScope) { this._state.change({ searchScope: null }, true); diff --git a/src/vs/editor/contrib/find/findModel.ts b/src/vs/editor/contrib/find/findModel.ts index 70846107cc..4b62ff88d8 100644 --- a/src/vs/editor/contrib/find/findModel.ts +++ b/src/vs/editor/contrib/find/findModel.ts @@ -59,6 +59,7 @@ export const FIND_IDS = { ToggleWholeWordCommand: 'toggleFindWholeWord', ToggleRegexCommand: 'toggleFindRegex', ToggleSearchScopeCommand: 'toggleFindInSelection', + TogglePreserveCaseCommand: 'togglePreserveCase', ReplaceOneAction: 'editor.action.replaceOne', ReplaceAllAction: 'editor.action.replaceAll', SelectAllMatchesAction: 'editor.action.selectAllMatches' @@ -416,11 +417,11 @@ export class FindModelBoundToEditorModel { let replacePattern = this._getReplacePattern(); let selection = this._editor.getSelection(); - let nextMatch = this._getNextMatch(selection.getStartPosition(), replacePattern.hasReplacementPatterns, false); + let nextMatch = this._getNextMatch(selection.getStartPosition(), true, false); if (nextMatch) { if (selection.equalsRange(nextMatch.range)) { // selection sits on a find match => replace it! - let replaceString = replacePattern.buildReplaceString(nextMatch.matches); + let replaceString = replacePattern.buildReplaceString(nextMatch.matches, this._state.preserveCase); let command = new ReplaceCommand(selection, replaceString); @@ -482,12 +483,14 @@ export class FindModelBoundToEditorModel { const replacePattern = this._getReplacePattern(); let resultText: string; + const preserveCase = this._state.preserveCase; + if (replacePattern.hasReplacementPatterns) { resultText = modelText.replace(searchRegex, function () { - return replacePattern.buildReplaceString(arguments); + return replacePattern.buildReplaceString(arguments, preserveCase); }); } else { - resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null)); + resultText = modelText.replace(searchRegex, replacePattern.buildReplaceString(null, preserveCase)); } let command = new ReplaceCommandThatPreservesSelection(fullModelRange, resultText, this._editor.getSelection()); @@ -501,7 +504,7 @@ export class FindModelBoundToEditorModel { let replaceStrings: string[] = []; for (let i = 0, len = matches.length; i < len; i++) { - replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches); + replaceStrings[i] = replacePattern.buildReplaceString(matches[i].matches, this._state.preserveCase); } let command = new ReplaceAllCommand(this._editor.getSelection(), matches.map(m => m.range), replaceStrings); diff --git a/src/vs/editor/contrib/find/findState.ts b/src/vs/editor/contrib/find/findState.ts index 339f248079..42fec44612 100644 --- a/src/vs/editor/contrib/find/findState.ts +++ b/src/vs/editor/contrib/find/findState.ts @@ -18,6 +18,7 @@ export interface FindReplaceStateChangedEvent { isRegex: boolean; wholeWord: boolean; matchCase: boolean; + preserveCase: boolean; searchScope: boolean; matchesPosition: boolean; matchesCount: boolean; @@ -41,6 +42,8 @@ export interface INewFindReplaceState { wholeWordOverride?: FindOptionOverride; matchCase?: boolean; matchCaseOverride?: FindOptionOverride; + preserveCase?: boolean; + preserveCaseOverride?: FindOptionOverride; searchScope?: Range | null; } @@ -65,6 +68,8 @@ export class FindReplaceState implements IDisposable { private _wholeWordOverride: FindOptionOverride; private _matchCase: boolean; private _matchCaseOverride: FindOptionOverride; + private _preserveCase: boolean; + private _preserveCaseOverride: FindOptionOverride; private _searchScope: Range | null; private _matchesPosition: number; private _matchesCount: number; @@ -78,10 +83,12 @@ export class FindReplaceState implements IDisposable { public get isRegex(): boolean { return effectiveOptionValue(this._isRegexOverride, this._isRegex); } public get wholeWord(): boolean { return effectiveOptionValue(this._wholeWordOverride, this._wholeWord); } public get matchCase(): boolean { return effectiveOptionValue(this._matchCaseOverride, this._matchCase); } + public get preserveCase(): boolean { return effectiveOptionValue(this._preserveCaseOverride, this._preserveCase); } public get actualIsRegex(): boolean { return this._isRegex; } public get actualWholeWord(): boolean { return this._wholeWord; } public get actualMatchCase(): boolean { return this._matchCase; } + public get actualPreserveCase(): boolean { return this._preserveCase; } public get searchScope(): Range | null { return this._searchScope; } public get matchesPosition(): number { return this._matchesPosition; } @@ -100,6 +107,8 @@ export class FindReplaceState implements IDisposable { this._wholeWordOverride = FindOptionOverride.NotSet; this._matchCase = false; this._matchCaseOverride = FindOptionOverride.NotSet; + this._preserveCase = false; + this._preserveCaseOverride = FindOptionOverride.NotSet; this._searchScope = null; this._matchesPosition = 0; this._matchesCount = 0; @@ -120,6 +129,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -169,6 +179,7 @@ export class FindReplaceState implements IDisposable { isRegex: false, wholeWord: false, matchCase: false, + preserveCase: false, searchScope: false, matchesPosition: false, matchesCount: false, @@ -179,6 +190,7 @@ export class FindReplaceState implements IDisposable { const oldEffectiveIsRegex = this.isRegex; const oldEffectiveWholeWords = this.wholeWord; const oldEffectiveMatchCase = this.matchCase; + const oldEffectivePreserveCase = this.preserveCase; if (typeof newState.searchString !== 'undefined') { if (this._searchString !== newState.searchString) { @@ -217,6 +229,9 @@ export class FindReplaceState implements IDisposable { if (typeof newState.matchCase !== 'undefined') { this._matchCase = newState.matchCase; } + if (typeof newState.preserveCase !== 'undefined') { + this._preserveCase = newState.preserveCase; + } if (typeof newState.searchScope !== 'undefined') { if (!Range.equalsRange(this._searchScope, newState.searchScope)) { this._searchScope = newState.searchScope; @@ -229,6 +244,7 @@ export class FindReplaceState implements IDisposable { this._isRegexOverride = (typeof newState.isRegexOverride !== 'undefined' ? newState.isRegexOverride : FindOptionOverride.NotSet); this._wholeWordOverride = (typeof newState.wholeWordOverride !== 'undefined' ? newState.wholeWordOverride : FindOptionOverride.NotSet); this._matchCaseOverride = (typeof newState.matchCaseOverride !== 'undefined' ? newState.matchCaseOverride : FindOptionOverride.NotSet); + this._preserveCaseOverride = (typeof newState.preserveCaseOverride !== 'undefined' ? newState.preserveCaseOverride : FindOptionOverride.NotSet); if (oldEffectiveIsRegex !== this.isRegex) { somethingChanged = true; @@ -243,6 +259,11 @@ export class FindReplaceState implements IDisposable { changeEvent.matchCase = true; } + if (oldEffectivePreserveCase !== this.preserveCase) { + somethingChanged = true; + changeEvent.preserveCase = true; + } + if (somethingChanged) { this._onFindReplaceStateChange.fire(changeEvent); } diff --git a/src/vs/editor/contrib/find/findWidget.css b/src/vs/editor/contrib/find/findWidget.css index d1aa36c7ff..4cd424b441 100644 --- a/src/vs/editor/contrib/find/findWidget.css +++ b/src/vs/editor/contrib/find/findWidget.css @@ -39,6 +39,11 @@ transition: top 200ms linear; padding: 0 4px; } + +.monaco-editor .find-widget.hiddenEditor { + display: none; +} + /* Find widget when replace is toggled on */ .monaco-editor .find-widget.replaceToggled { top: -74px; /* find input height + replace input height + shadow (10px) */ @@ -79,6 +84,15 @@ height: 25px; } +.monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input { + width: 100% !important; + padding-right: 66px; +} + +.monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { + padding-right: 22px; +} + .monaco-editor .find-widget > .find-part .monaco-inputbox > .wrapper > .input, .monaco-editor .find-widget > .replace-part .monaco-inputbox > .wrapper > .input { padding-top: 2px; @@ -224,12 +238,19 @@ } .monaco-editor .find-widget > .replace-part > .replace-input { + position: relative; display: flex; display: -webkit-flex; vertical-align: middle; width: auto !important; } +.monaco-editor .find-widget > .replace-part > .replace-input > .controls { + position: absolute; + top: 3px; + right: 2px; +} + /* REDUCED */ .monaco-editor .find-widget.reduced-find-widget .matchesCount, .monaco-editor .find-widget.reduced-find-widget .monaco-checkbox { diff --git a/src/vs/editor/contrib/find/findWidget.ts b/src/vs/editor/contrib/find/findWidget.ts index 1ae110b1dc..babcee896d 100644 --- a/src/vs/editor/contrib/find/findWidget.ts +++ b/src/vs/editor/contrib/find/findWidget.ts @@ -13,6 +13,7 @@ import { FindInput, IFindInputStyles } from 'vs/base/browser/ui/findinput/findIn import { HistoryInputBox, IMessage as InputBoxMessage } from 'vs/base/browser/ui/inputbox/inputBox'; import { IHorizontalSashLayoutProvider, ISashEvent, Orientation, Sash } from 'vs/base/browser/ui/sash/sash'; import { Widget } from 'vs/base/browser/ui/widget'; +import { Checkbox } from 'vs/base/browser/ui/checkbox/checkbox'; import { Delayer } from 'vs/base/common/async'; import { Color } from 'vs/base/common/color'; import { onUnexpectedError } from 'vs/base/common/errors'; @@ -47,6 +48,7 @@ const NLS_TOGGLE_SELECTION_FIND_TITLE = nls.localize('label.toggleSelectionFind' const NLS_CLOSE_BTN_LABEL = nls.localize('label.closeButton', "Close"); const NLS_REPLACE_INPUT_LABEL = nls.localize('label.replace', "Replace"); const NLS_REPLACE_INPUT_PLACEHOLDER = nls.localize('placeholder.replace', "Replace"); +const NLS_PRESERVE_CASE_LABEL = nls.localize('label.preserveCaseCheckbox', "Preserve Case"); const NLS_REPLACE_BTN_LABEL = nls.localize('label.replaceButton', "Replace"); const NLS_REPLACE_ALL_BTN_LABEL = nls.localize('label.replaceAllButton', "Replace All"); const NLS_TOGGLE_REPLACE_MODE_BTN_LABEL = nls.localize('label.toggleReplaceButton', "Toggle Replace mode"); @@ -101,6 +103,7 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas private _nextBtn: SimpleButton; private _toggleSelectionFind: SimpleCheckbox; private _closeBtn: SimpleButton; + private _preserveCase: Checkbox; private _replaceBtn: SimpleButton; private _replaceAllBtn: SimpleButton; @@ -590,14 +593,26 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas }; this._findInput.style(inputStyles); this._replaceInputBox.style(inputStyles); + this._preserveCase.style(inputStyles); } private _tryUpdateWidgetWidth() { if (!this._isVisible) { return; } - let editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; - let minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; + + const editorContentWidth = this._codeEditor.getConfiguration().layoutInfo.contentWidth; + + if (editorContentWidth <= 0) { + // for example, diff view original editor + dom.addClass(this._domNode, 'hiddenEditor'); + return; + } else if (dom.hasClass(this._domNode, 'hiddenEditor')) { + dom.removeClass(this._domNode, 'hiddenEditor'); + } + + const editorWidth = this._codeEditor.getConfiguration().layoutInfo.width; + const minimapWidth = this._codeEditor.getConfiguration().layoutInfo.minimapWidth; let collapsedFindWidget = false; let reducedFindWidget = false; let narrowFindWidget = false; @@ -913,6 +928,19 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas this._state.change({ replaceString: this._replaceInputBox.value }, false); })); + this._preserveCase = this._register(new Checkbox({ + actionClassName: 'monaco-case-sensitive', + title: NLS_PRESERVE_CASE_LABEL, + isChecked: false, + })); + this._preserveCase.checked = !!this._state.preserveCase; + this._register(this._preserveCase.onChange(viaKeyboard => { + if (!viaKeyboard) { + this._state.change({ preserveCase: !this._state.preserveCase }, false); + this._replaceInputBox.focus(); + } + })); + // Replace one button this._replaceBtn = this._register(new SimpleButton({ label: NLS_REPLACE_BTN_LABEL + this._keybindingLabelFor(FIND_IDS.ReplaceOneAction), @@ -937,6 +965,12 @@ export class FindWidget extends Widget implements IOverlayWidget, IHorizontalSas } })); + let controls = document.createElement('div'); + controls.className = 'controls'; + controls.style.display = 'block'; + controls.appendChild(this._preserveCase.domNode); + replaceInput.appendChild(controls); + let replacePart = document.createElement('div'); replacePart.className = 'replace-part'; replacePart.appendChild(replaceInput); diff --git a/src/vs/editor/contrib/find/replacePattern.ts b/src/vs/editor/contrib/find/replacePattern.ts index c47463ea90..581062f875 100644 --- a/src/vs/editor/contrib/find/replacePattern.ts +++ b/src/vs/editor/contrib/find/replacePattern.ts @@ -4,6 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { CharCode } from 'vs/base/common/charCode'; +import { containsUppercaseCharacter } from 'vs/base/common/strings'; const enum ReplacePatternKind { StaticValue = 0, @@ -48,9 +49,22 @@ export class ReplacePattern { } } - public buildReplaceString(matches: string[] | null): string { + public buildReplaceString(matches: string[] | null, preserveCase?: boolean): string { if (this._state.kind === ReplacePatternKind.StaticValue) { - return this._state.staticValue; + if (preserveCase && matches && (matches[0] !== '')) { + if (matches[0].toUpperCase() === matches[0]) { + return this._state.staticValue.toUpperCase(); + } else if (matches[0].toLowerCase() === matches[0]) { + return this._state.staticValue.toLowerCase(); + } else if (containsUppercaseCharacter(matches[0][0])) { + return this._state.staticValue[0].toUpperCase() + this._state.staticValue.substr(1); + } else { + // we don't understand its pattern yet. + return this._state.staticValue; + } + } else { + return this._state.staticValue; + } } let result = ''; diff --git a/src/vs/editor/contrib/find/simpleFindWidget.ts b/src/vs/editor/contrib/find/simpleFindWidget.ts index 6807fe2424..8277a12054 100644 --- a/src/vs/editor/contrib/find/simpleFindWidget.ts +++ b/src/vs/editor/contrib/find/simpleFindWidget.ts @@ -41,7 +41,8 @@ export abstract class SimpleFindWidget extends Widget { @IContextViewService private readonly _contextViewService: IContextViewService, @IContextKeyService contextKeyService: IContextKeyService, private readonly _state: FindReplaceState = new FindReplaceState(), - showOptionButtons?: boolean + showOptionButtons?: boolean, + private readonly _invertDefaultDirection: boolean = false ) { super(); @@ -93,13 +94,13 @@ export abstract class SimpleFindWidget extends Widget { this._register(this._findInput.onKeyDown((e) => { if (e.equals(KeyCode.Enter)) { - this.find(false); + this.find(this._invertDefaultDirection); e.preventDefault(); return; } if (e.equals(KeyMod.Shift | KeyCode.Enter)) { - this.find(true); + this.find(!this._invertDefaultDirection); e.preventDefault(); return; } @@ -295,4 +296,4 @@ registerThemingParticipant((theme, collector) => { if (widgetShadowColor) { collector.addRule(`.monaco-workbench .simple-find-part { box-shadow: 0 2px 8px ${widgetShadowColor}; }`); } -}); \ No newline at end of file +}); diff --git a/src/vs/editor/contrib/find/test/replacePattern.test.ts b/src/vs/editor/contrib/find/test/replacePattern.test.ts index 83be09db4c..bc22aaff5c 100644 --- a/src/vs/editor/contrib/find/test/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/replacePattern.test.ts @@ -153,4 +153,26 @@ suite('Replace Pattern test', () => { let actual = replacePattern.buildReplaceString(matches); assert.equal(actual, 'a{}'); }); + + test('preserve case', () => { + let replacePattern = parseReplaceString('Def'); + let actual = replacePattern.buildReplaceString(['abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['abc', 'Abc'], true); + assert.equal(actual, 'def'); + actual = replacePattern.buildReplaceString(['Abc', 'abc'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['ABC', 'abc'], true); + assert.equal(actual, 'DEF'); + + actual = replacePattern.buildReplaceString(['AbC'], true); + assert.equal(actual, 'Def'); + actual = replacePattern.buildReplaceString(['aBC'], true); + assert.equal(actual, 'Def'); + }); }); diff --git a/src/vs/editor/contrib/indentation/indentation.ts b/src/vs/editor/contrib/indentation/indentation.ts index 4b89666da4..5577359b2e 100644 --- a/src/vs/editor/contrib/indentation/indentation.ts +++ b/src/vs/editor/contrib/indentation/indentation.ts @@ -589,13 +589,13 @@ export class AutoIndentOnPaste implements IEditorContribution { private shouldIgnoreLine(model: ITextModel, lineNumber: number): boolean { model.forceTokenization(lineNumber); - let nonWhiteSpaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); - if (nonWhiteSpaceColumn === 0) { + let nonWhitespaceColumn = model.getLineFirstNonWhitespaceColumn(lineNumber); + if (nonWhitespaceColumn === 0) { return true; } let tokens = model.getLineTokens(lineNumber); if (tokens.getCount() > 0) { - let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhiteSpaceColumn); + let firstNonWhitespaceTokenIndex = tokens.findTokenIndexAtOffset(nonWhitespaceColumn); if (firstNonWhitespaceTokenIndex >= 0 && tokens.getStandardTokenType(firstNonWhitespaceTokenIndex) === StandardTokenType.Comment) { return true; } diff --git a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts index e767cc22ac..30792d634d 100644 --- a/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts +++ b/src/vs/editor/contrib/suggest/suggestCommitCharacters.ts @@ -36,10 +36,17 @@ export class CommitCharacterController { private _onItem(selected: ISelectedSuggestion | undefined): void { if (!selected || !isNonEmptyArray(selected.item.completion.commitCharacters)) { + // no item or no commit characters this.reset(); return; } + if (this._active && this._active.item.item === selected.item) { + // still the same item + return; + } + + // keep item and its commit characters const acceptCharacters = new CharacterSet(); for (const ch of selected.item.completion.commitCharacters) { if (ch.length > 0) { diff --git a/src/vs/editor/contrib/suggest/suggestWidget.ts b/src/vs/editor/contrib/suggest/suggestWidget.ts index 415afc45cb..19f1ac6631 100644 --- a/src/vs/editor/contrib/suggest/suggestWidget.ts +++ b/src/vs/editor/contrib/suggest/suggestWidget.ts @@ -50,7 +50,7 @@ interface ISuggestionTemplateData { iconLabel: IconLabel; typeLabel: HTMLElement; readMore: HTMLElement; - disposables: IDisposable[]; + disposables: DisposableStore; } /** @@ -106,8 +106,7 @@ class Renderer implements IListRenderer renderTemplate(container: HTMLElement): ISuggestionTemplateData { const data = Object.create(null); - const disposables = new DisposableStore(); - data.disposables = [disposables]; + data.disposables = new DisposableStore(); data.root = container; addClass(data.root, 'show-file-icons'); @@ -119,7 +118,7 @@ class Renderer implements IListRenderer const main = append(text, $('.main')); data.iconLabel = new IconLabel(main, { supportHighlights: true }); - disposables.add(data.iconLabel); + data.disposables.add(data.iconLabel); data.typeLabel = append(main, $('span.type-label')); @@ -147,7 +146,7 @@ class Renderer implements IListRenderer configureFont(); - disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) + data.disposables.add(Event.chain(this.editor.onDidChangeConfiguration.bind(this.editor)) .filter(e => e.fontInfo || e.contribInfo) .on(configureFont, null)); @@ -218,7 +217,7 @@ class Renderer implements IListRenderer } disposeTemplate(templateData: ISuggestionTemplateData): void { - templateData.disposables = dispose(templateData.disposables); + templateData.disposables.dispose(); } } @@ -253,7 +252,7 @@ class SuggestionDetails { private type: HTMLElement; private docs: HTMLElement; private ariaLabel: string | null; - private disposables: IDisposable[]; + private readonly disposables: DisposableStore; private renderDisposeable: IDisposable; private borderWidth: number = 1; @@ -264,16 +263,16 @@ class SuggestionDetails { private readonly markdownRenderer: MarkdownRenderer, private readonly triggerKeybindingLabel: string, ) { - this.disposables = []; + this.disposables = new DisposableStore(); this.el = append(container, $('.details')); - this.disposables.push(toDisposable(() => container.removeChild(this.el))); + this.disposables.add(toDisposable(() => container.removeChild(this.el))); this.body = $('.body'); this.scrollbar = new DomScrollableElement(this.body, {}); append(this.el, this.scrollbar.getDomNode()); - this.disposables.push(this.scrollbar); + this.disposables.add(this.scrollbar); this.header = append(this.body, $('.header')); this.close = append(this.header, $('span.close')); @@ -414,7 +413,7 @@ class SuggestionDetails { } dispose(): void { - this.disposables = dispose(this.disposables); + this.disposables.dispose(); this.renderDisposeable = dispose(this.renderDisposeable); } } @@ -672,7 +671,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.list.length < index) { + if (index >= this.list.length || item !== this.list.element(index)) { return; } @@ -689,11 +688,7 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { - if (this.focusedItem === item) { - this.currentSuggestionDetails = null; - } - }); + }).catch(onUnexpectedError); } // emit an event @@ -810,12 +805,11 @@ export class SuggestWidget implements IContentWidget, IListVirtualDelegate { assert.deepEqual(actual, EXPECTED); }); + test('cursorWordLeftSelect - issue #74369: cursorWordLeft and cursorWordLeftSelect do not behave consistently', () => { + const EXPECTED = [ + '|this.|is.|a.|test', + ].join('\n'); + const [text,] = deserializePipePositions(EXPECTED); + const actualStops = testRepeatedActionAndExtractPositions( + text, + new Position(1, 15), + ed => cursorWordLeft(ed, true), + ed => ed.getPosition()!, + ed => ed.getPosition()!.equals(new Position(1, 1)) + ); + const actual = serializePipePositions(text, actualStops); + assert.deepEqual(actual, EXPECTED); + }); + test('cursorWordStartLeft', () => { // This is the behaviour observed in Visual Studio, please do not touch test const EXPECTED = ['| |/* |Just |some |more |text |a|+= |3 |+|5|-|3 |+ |7 |*/| '].join('\n'); diff --git a/src/vs/editor/contrib/wordOperations/wordOperations.ts b/src/vs/editor/contrib/wordOperations/wordOperations.ts index b45f176a7b..ab9301c627 100644 --- a/src/vs/editor/contrib/wordOperations/wordOperations.ts +++ b/src/vs/editor/contrib/wordOperations/wordOperations.ts @@ -163,7 +163,7 @@ export class CursorWordLeftSelect extends WordLeftCommand { constructor() { super({ inSelectionMode: true, - wordNavigationType: WordNavigationType.WordStart, + wordNavigationType: WordNavigationType.WordStartFast, id: 'cursorWordLeftSelect', precondition: undefined }); diff --git a/src/vs/editor/standalone/browser/simpleServices.ts b/src/vs/editor/standalone/browser/simpleServices.ts index 8c4d7744da..c21e4eb245 100644 --- a/src/vs/editor/standalone/browser/simpleServices.ts +++ b/src/vs/editor/standalone/browser/simpleServices.ts @@ -234,7 +234,9 @@ export class StandaloneCommandService implements ICommandService { private readonly _dynamicCommands: { [id: string]: ICommand; }; private readonly _onWillExecuteCommand = new Emitter(); + private readonly _onDidExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; @@ -256,8 +258,10 @@ export class StandaloneCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); @@ -352,7 +356,7 @@ export class StandaloneKeybindingService extends AbstractKeybindingService { private _toNormalizedKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { diff --git a/src/vs/editor/standalone/browser/standaloneServices.ts b/src/vs/editor/standalone/browser/standaloneServices.ts index 02400fadf1..3e9486a6e3 100644 --- a/src/vs/editor/standalone/browser/standaloneServices.ts +++ b/src/vs/editor/standalone/browser/standaloneServices.ts @@ -140,8 +140,6 @@ export module StaticServices { export const notificationService = define(INotificationService, () => new SimpleNotificationService()); - export const accessibilityService = define(IAccessibilityService, () => new BrowserAccessibilityService()); - export const markerService = define(IMarkerService, () => new MarkerService()); export const modeService = define(IModeService, (o) => new ModeServiceImpl()); @@ -194,6 +192,8 @@ export class DynamicStandaloneServices extends Disposable { let contextKeyService = ensure(IContextKeyService, () => this._register(new ContextKeyService(configurationService))); + ensure(IAccessibilityService, () => new BrowserAccessibilityService(contextKeyService, configurationService)); + ensure(IListService, () => new ListService(contextKeyService)); let commandService = ensure(ICommandService, () => new StandaloneCommandService(this._instantiationService)); diff --git a/src/vs/editor/test/browser/controller/cursor.test.ts b/src/vs/editor/test/browser/controller/cursor.test.ts index 8fc1cfcbe3..f49f80b3c6 100644 --- a/src/vs/editor/test/browser/controller/cursor.test.ts +++ b/src/vs/editor/test/browser/controller/cursor.test.ts @@ -4344,12 +4344,12 @@ suite('autoClosingPairs', () => { let autoClosePositions = [ 'var a |=| [|]|;|', 'var b |=| |`asd`|;|', - 'var c |=| |\'asd!\'|;|', + 'var c |=| |\'asd\'|;|', 'var d |=| |"asd"|;|', 'var e |=| /*3*/| 3;|', 'var f |=| /**| 3 */3;|', 'var g |=| (3+5)|;|', - 'var h |=| {| a:| |\'value!\'| |}|;|', + 'var h |=| {| a:| |\'value\'| |}|;|', ]; for (let i = 0, len = autoClosePositions.length; i < len; i++) { const lineNumber = i + 1; @@ -4494,6 +4494,107 @@ suite('autoClosingPairs', () => { mode.dispose(); }); + test('issue #37315 - overtypes only those characters that it inserted', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: 'asd' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // overtype! + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(asd)'); + + // do not overtype! + cursor.setSelections('test', [new Selection(2, 4, 2, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(2), 'y=());'); + + }); + mode.dispose(); + }); + + test('issue #37315 - stops overtyping once cursor leaves area', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 5, 1, 5)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it overtypes only once', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursor.setSelections('test', [new Selection(1, 4, 1, 4)]); + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=())'); + }); + mode.dispose(); + }); + + test('issue #37315 - it can remember multiple auto-closed instances', () => { + let mode = new AutoClosingMode(); + usingCursor({ + text: [ + '', + 'y=();' + ], + languageIdentifier: mode.getLanguageIdentifier() + }, (model, cursor) => { + assertCursor(cursor, new Position(1, 1)); + + cursorCommand(cursor, H.Type, { text: 'x=(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=()'); + + cursorCommand(cursor, H.Type, { text: '(' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + + cursorCommand(cursor, H.Type, { text: ')' }, 'keyboard'); + assert.strictEqual(model.getLineContent(1), 'x=(())'); + }); + mode.dispose(); + }); + test('issue #15825: accents on mac US intl keyboard', () => { let mode = new AutoClosingMode(); usingCursor({ diff --git a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts index 88d1bd3519..ce2119c87f 100644 --- a/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts +++ b/src/vs/editor/test/browser/controller/cursorMoveCommand.test.ts @@ -132,7 +132,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -140,7 +140,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first non white space character', () => { moveTo(thisCursor, 1, 6); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -148,7 +148,7 @@ suite('Cursor move command test', () => { test('move to first non white space character of line from first character', () => { moveTo(thisCursor, 1, 1); - moveToLineFirstNonWhiteSpaceCharacter(thisCursor); + moveToLineFirstNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 6); }); @@ -180,7 +180,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from middle', () => { moveTo(thisCursor, 1, 8); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -188,7 +188,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from last non white space character', () => { moveTo(thisCursor, 1, 19); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -196,7 +196,7 @@ suite('Cursor move command test', () => { test('move to last non white space character from line end', () => { moveTo(thisCursor, 1, 21); - moveToLineLastNonWhiteSpaceCharacter(thisCursor); + moveToLineLastNonWhitespaceCharacter(thisCursor); cursorEqual(thisCursor, 1, 19); }); @@ -415,7 +415,7 @@ function moveToLineStart(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineStart }); } -function moveToLineFirstNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineFirstNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineFirstNonWhitespaceCharacter }); } @@ -427,7 +427,7 @@ function moveToLineEnd(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineEnd }); } -function moveToLineLastNonWhiteSpaceCharacter(cursor: Cursor) { +function moveToLineLastNonWhitespaceCharacter(cursor: Cursor) { move(cursor, { to: CursorMove.RawDirection.WrappedLineLastNonWhitespaceCharacter }); } diff --git a/src/vs/editor/test/browser/editorTestServices.ts b/src/vs/editor/test/browser/editorTestServices.ts index a00104b99c..2b4fb94972 100644 --- a/src/vs/editor/test/browser/editorTestServices.ts +++ b/src/vs/editor/test/browser/editorTestServices.ts @@ -32,6 +32,9 @@ export class TestCommandService implements ICommandService { private readonly _onWillExecuteCommand = new Emitter(); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor(instantiationService: IInstantiationService) { this._instantiationService = instantiationService; } @@ -43,8 +46,9 @@ export class TestCommandService implements ICommandService { } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]) as T; + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/editor/test/browser/services/openerService.test.ts b/src/vs/editor/test/browser/services/openerService.test.ts index e9ca426999..2450a860d0 100644 --- a/src/vs/editor/test/browser/services/openerService.test.ts +++ b/src/vs/editor/test/browser/services/openerService.test.ts @@ -17,6 +17,7 @@ suite('OpenerService', function () { const commandService = new class implements ICommandService { _serviceBrand: any; onWillExecuteCommand = () => ({ dispose: () => { } }); + onDidExecuteCommand = () => ({ dispose: () => { } }); executeCommand(id: string, ...args: any[]): Promise { lastCommand = { id, args }; return Promise.resolve(undefined); diff --git a/src/vs/editor/test/common/model/textModelSearch.test.ts b/src/vs/editor/test/common/model/textModelSearch.test.ts index 1d918b69e8..c9f79b5997 100644 --- a/src/vs/editor/test/common/model/textModelSearch.test.ts +++ b/src/vs/editor/test/common/model/textModelSearch.test.ts @@ -733,4 +733,23 @@ suite('TextModelSearch', () => { assert(isMultilineRegexSource('\\n')); assert(isMultilineRegexSource('foo\\W')); }); + + test('issue #74715. \\d* finds empty string and stops searching.', () => { + let model = TextModel.createFromString('10.243.30.10'); + + let searchParams = new SearchParams('\\d*', true, false, null); + + let actual = TextModelSearch.findMatches(model, searchParams, model.getFullModelRange(), true, 100); + assert.deepEqual(actual, [ + new FindMatch(new Range(1, 1, 1, 3), ['10']), + new FindMatch(new Range(1, 3, 1, 3), ['']), + new FindMatch(new Range(1, 4, 1, 7), ['243']), + new FindMatch(new Range(1, 7, 1, 7), ['']), + new FindMatch(new Range(1, 8, 1, 10), ['30']), + new FindMatch(new Range(1, 10, 1, 10), ['']), + new FindMatch(new Range(1, 11, 1, 13), ['10']) + ]); + + model.dispose(); + }); }); diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 0f5aec0e29..66893ff470 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -5,6 +5,8 @@ declare namespace monaco { + // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. + export type Thenable = PromiseLike; export interface IDisposable { @@ -27,7 +29,8 @@ declare namespace monaco { export enum MarkerTag { - Unnecessary = 1 + Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { @@ -583,6 +586,14 @@ declare namespace monaco { * Test if `otherRange` is in `range`. If the ranges are equal, will return true. */ static containsRange(range: IRange, otherRange: IRange): boolean; + /** + * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. + */ + strictContainsRange(range: IRange): boolean; + /** + * Test if `otherRange` is strinctly in `range` (must start after, and end before). If the ranges are equal, will return false. + */ + static strictContainsRange(range: IRange, otherRange: IRange): boolean; /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. diff --git a/src/vs/platform/accessibility/common/abstractAccessibilityService.ts b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts new file mode 100644 index 0000000000..671d0ba86e --- /dev/null +++ b/src/vs/platform/accessibility/common/abstractAccessibilityService.ts @@ -0,0 +1,43 @@ +/*--------------------------------------------------------------------------------------------- + * 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 { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; +import { Event, Emitter } from 'vs/base/common/event'; +import { IContextKey, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; + +export abstract class AbstractAccessibilityService extends Disposable implements IAccessibilityService { + _serviceBrand: any; + + private _accessibilityModeEnabledContext: IContextKey; + protected readonly _onDidChangeAccessibilitySupport = new Emitter(); + readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; + + constructor( + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService); + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.accessibilitySupport')) { + this._updateContextKey(); + } + })); + this._updateContextKey(); + this.onDidChangeAccessibilitySupport(() => this._updateContextKey()); + } + + abstract alwaysUnderlineAccessKeys(): Promise; + abstract getAccessibilitySupport(): AccessibilitySupport; + abstract setAccessibilitySupport(accessibilitySupport: AccessibilitySupport): void; + + private _updateContextKey(): void { + const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled; + const config = this._configurationService.getValue('editor.accessibilitySupport'); + this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected)); + } +} \ No newline at end of file diff --git a/src/vs/platform/accessibility/common/accessibility.ts b/src/vs/platform/accessibility/common/accessibility.ts index b267735214..4f53efbe1a 100644 --- a/src/vs/platform/accessibility/common/accessibility.ts +++ b/src/vs/platform/accessibility/common/accessibility.ts @@ -5,6 +5,7 @@ import { createDecorator } from 'vs/platform/instantiation/common/instantiation'; import { Event } from 'vs/base/common/event'; +import { RawContextKey } from 'vs/platform/contextkey/common/contextkey'; export const IAccessibilityService = createDecorator('accessibilityService'); @@ -28,3 +29,5 @@ export const enum AccessibilitySupport { Enabled = 2 } + +export const CONTEXT_ACCESSIBILITY_MODE_ENABLED = new RawContextKey('accessibilityModeEnabled', false); diff --git a/src/vs/platform/accessibility/common/accessibilityService.ts b/src/vs/platform/accessibility/common/accessibilityService.ts index f40805e770..68f53da6b5 100644 --- a/src/vs/platform/accessibility/common/accessibilityService.ts +++ b/src/vs/platform/accessibility/common/accessibilityService.ts @@ -4,17 +4,34 @@ *--------------------------------------------------------------------------------------------*/ import { Emitter, Event } from 'vs/base/common/event'; -import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { IAccessibilityService, AccessibilitySupport, CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; import { Disposable } from 'vs/base/common/lifecycle'; +import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; export class BrowserAccessibilityService extends Disposable implements IAccessibilityService { _serviceBrand: any; private _accessibilitySupport = AccessibilitySupport.Unknown; + private _accessibilityModeEnabledContext: IContextKey; private readonly _onDidChangeAccessibilitySupport = new Emitter(); readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; + constructor( + @IContextKeyService private readonly _contextKeyService: IContextKeyService, + @IConfigurationService private readonly _configurationService: IConfigurationService, + ) { + super(); + this._accessibilityModeEnabledContext = CONTEXT_ACCESSIBILITY_MODE_ENABLED.bindTo(this._contextKeyService); + this._register(this._configurationService.onDidChangeConfiguration(e => { + if (e.affectsConfiguration('editor.accessibilitySupport')) { + this._updateContextKey(); + } + })); + this._updateContextKey(); + } + alwaysUnderlineAccessKeys(): Promise { return Promise.resolve(false); } @@ -26,9 +43,16 @@ export class BrowserAccessibilityService extends Disposable implements IAccessib this._accessibilitySupport = accessibilitySupport; this._onDidChangeAccessibilitySupport.fire(); + this._updateContextKey(); } getAccessibilitySupport(): AccessibilitySupport { return this._accessibilitySupport; } + + private _updateContextKey(): void { + const detected = this.getAccessibilitySupport() === AccessibilitySupport.Enabled; + const config = this._configurationService.getValue('editor.accessibilitySupport'); + this._accessibilityModeEnabledContext.set(config === 'on' || (config === 'auto' && detected)); + } } diff --git a/src/vs/platform/browser/contextScopedHistoryWidget.ts b/src/vs/platform/browser/contextScopedHistoryWidget.ts index 3e36c8c5ca..7a5c3bf9b3 100644 --- a/src/vs/platform/browser/contextScopedHistoryWidget.ts +++ b/src/vs/platform/browser/contextScopedHistoryWidget.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IContextKeyService, ContextKeyDefinedExpr, ContextKeyExpr, ContextKeyAndExpr, ContextKeyEqualsExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr, RawContextKey, IContextKey, IContextKeyServiceTarget } from 'vs/platform/contextkey/common/contextkey'; import { HistoryInputBox, IHistoryInputOptions } from 'vs/base/browser/ui/inputbox/inputBox'; import { FindInput, IFindInputOptions } from 'vs/base/browser/ui/findinput/findInput'; import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview'; @@ -66,7 +66,7 @@ export class ContextScopedFindInput extends FindInput { KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showPrevious', weight: KeybindingWeight.WorkbenchContrib, - when: ContextKeyExpr.and(new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.UpArrow, secondary: [KeyMod.Alt | KeyCode.UpArrow], handler: (accessor, arg2) => { @@ -81,7 +81,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'history.showNext', weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyAndExpr([new ContextKeyDefinedExpr(HistoryNavigationWidgetContext), new ContextKeyEqualsExpr(HistoryNavigationEnablementContext, true)]), + when: ContextKeyExpr.and(ContextKeyExpr.has(HistoryNavigationWidgetContext), ContextKeyExpr.equals(HistoryNavigationEnablementContext, true)), primary: KeyCode.DownArrow, secondary: [KeyMod.Alt | KeyCode.DownArrow], handler: (accessor, arg2) => { diff --git a/src/vs/platform/commands/common/commands.ts b/src/vs/platform/commands/common/commands.ts index 58f12c2950..6a950b0e75 100644 --- a/src/vs/platform/commands/common/commands.ts +++ b/src/vs/platform/commands/common/commands.ts @@ -15,11 +15,13 @@ export const ICommandService = createDecorator('commandService' export interface ICommandEvent { commandId: string; + args: any[]; } export interface ICommandService { _serviceBrand: any; onWillExecuteCommand: Event; + onDidExecuteCommand: Event; executeCommand(commandId: string, ...args: any[]): Promise; } @@ -135,6 +137,7 @@ export const CommandsRegistry: ICommandRegistry = new class implements ICommandR export const NullCommandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand() { return Promise.resolve(undefined); } diff --git a/src/vs/platform/configuration/test/node/configurationService.test.ts b/src/vs/platform/configuration/test/node/configurationService.test.ts index 1808dff780..565e7851d1 100644 --- a/src/vs/platform/configuration/test/node/configurationService.test.ts +++ b/src/vs/platform/configuration/test/node/configurationService.test.ts @@ -94,7 +94,8 @@ suite('ConfigurationService - Node', () => { const service = new ConfigurationService(URI.file(res.testFile)); await service.initialize(); return new Promise((c, e) => { - service.onDidChangeConfiguration(() => { + const disposable = service.onDidChangeConfiguration(() => { + disposable.dispose(); assert.equal(service.getValue('foo'), 'bar'); service.dispose(); c(); diff --git a/src/vs/platform/contextkey/common/contextkey.ts b/src/vs/platform/contextkey/common/contextkey.ts index 86a611b78f..5477c39f54 100644 --- a/src/vs/platform/contextkey/common/contextkey.ts +++ b/src/vs/platform/contextkey/common/contextkey.ts @@ -14,10 +14,10 @@ export const enum ContextKeyExprType { NotEquals = 4, And = 5, Regex = 6, - // {{SQL CARBON EDIT}} - GreaterThanEquals = 7, - LessThanEquals = 8 - // + NotRegex = 7, + Or = 8, + GreaterThanEquals = 9, // {{SQL CARBON EDIT}} add value + LessThanEquals = 10 // {{SQL CARBON EDIT}} add value } export interface IContextKeyExprMapper { @@ -31,27 +31,31 @@ export interface IContextKeyExprMapper { export abstract class ContextKeyExpr { public static has(key: string): ContextKeyExpr { - return new ContextKeyDefinedExpr(key); + return ContextKeyDefinedExpr.create(key); } public static equals(key: string, value: any): ContextKeyExpr { - return new ContextKeyEqualsExpr(key, value); + return ContextKeyEqualsExpr.create(key, value); } public static notEquals(key: string, value: any): ContextKeyExpr { - return new ContextKeyNotEqualsExpr(key, value); + return ContextKeyNotEqualsExpr.create(key, value); } public static regex(key: string, value: RegExp): ContextKeyExpr { - return new ContextKeyRegexExpr(key, value); + return ContextKeyRegexExpr.create(key, value); } public static not(key: string): ContextKeyExpr { - return new ContextKeyNotExpr(key); + return ContextKeyNotExpr.create(key); } - public static and(...expr: Array): ContextKeyExpr { - return new ContextKeyAndExpr(expr); + public static and(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyAndExpr.create(expr); + } + + public static or(...expr: Array): ContextKeyExpr | undefined { + return ContextKeyOrExpr.create(expr); } // {{SQL CARBON EDIT}} @@ -69,9 +73,17 @@ export abstract class ContextKeyExpr { return undefined; } + return this._deserializeOrExpression(serialized, strict); + } + + private static _deserializeOrExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { + let pieces = serialized.split('||'); + return ContextKeyOrExpr.create(pieces.map(p => this._deserializeAndExpression(p, strict))); + } + + private static _deserializeAndExpression(serialized: string, strict: boolean): ContextKeyExpr | undefined { let pieces = serialized.split('&&'); - let result = new ContextKeyAndExpr(pieces.map(p => this._deserializeOne(p, strict))); - return result.normalize(); + return ContextKeyAndExpr.create(pieces.map(p => this._deserializeOne(p, strict))); } private static _deserializeOne(serializedOne: string, strict: boolean): ContextKeyExpr { @@ -79,17 +91,17 @@ export abstract class ContextKeyExpr { if (serializedOne.indexOf('!=') >= 0) { let pieces = serializedOne.split('!='); - return new ContextKeyNotEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyNotEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('==') >= 0) { let pieces = serializedOne.split('=='); - return new ContextKeyEqualsExpr(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); + return ContextKeyEqualsExpr.create(pieces[0].trim(), this._deserializeValue(pieces[1], strict)); } if (serializedOne.indexOf('=~') >= 0) { let pieces = serializedOne.split('=~'); - return new ContextKeyRegexExpr(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); + return ContextKeyRegexExpr.create(pieces[0].trim(), this._deserializeRegexValue(pieces[1], strict)); } // {{SQL CARBON EDIT}} @@ -104,10 +116,10 @@ export abstract class ContextKeyExpr { // if (/^\!\s*/.test(serializedOne)) { - return new ContextKeyNotExpr(serializedOne.substr(1).trim()); + return ContextKeyNotExpr.create(serializedOne.substr(1).trim()); } - return new ContextKeyDefinedExpr(serializedOne); + return ContextKeyDefinedExpr.create(serializedOne); } private static _deserializeValue(serializedValue: string, strict: boolean): any { @@ -168,10 +180,10 @@ export abstract class ContextKeyExpr { public abstract getType(): ContextKeyExprType; public abstract equals(other: ContextKeyExpr): boolean; public abstract evaluate(context: IContext): boolean; - public abstract normalize(): ContextKeyExpr | undefined; public abstract serialize(): string; public abstract keys(): string[]; public abstract map(mapFnc: IContextKeyExprMapper): ContextKeyExpr; + public abstract negate(): ContextKeyExpr; } function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { @@ -191,19 +203,25 @@ function cmp(a: ContextKeyExpr, b: ContextKeyExpr): number { return (a).cmp(b); case ContextKeyExprType.Regex: return (a).cmp(b); - // {{SQL CARBON EDIT}} - case ContextKeyExprType.GreaterThanEquals: + case ContextKeyExprType.GreaterThanEquals: // {{SQL CARBON EDIT}} add case return (a).cmp(b); - case ContextKeyExprType.LessThanEquals: + case ContextKeyExprType.LessThanEquals: // {{SQL CARBON EDIT}} add case return (a).cmp(b); - // + case ContextKeyExprType.NotRegex: + return (a).cmp(b); + case ContextKeyExprType.And: + return (a).cmp(b); default: throw new Error('Unknown ContextKeyExpr!'); } } export class ContextKeyDefinedExpr implements ContextKeyExpr { - constructor(protected key: string) { + public static create(key: string): ContextKeyExpr { + return new ContextKeyDefinedExpr(key); + } + + protected constructor(protected key: string) { } public getType(): ContextKeyExprType { @@ -231,10 +249,6 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { return (!!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return this.key; } @@ -246,10 +260,25 @@ export class ContextKeyDefinedExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapDefined(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyNotExpr.create(this.key); + } } export class ContextKeyEqualsExpr implements ContextKeyExpr { - constructor(private readonly key: string, private readonly value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyDefinedExpr.create(key); + } + return ContextKeyNotExpr.create(key); + } + return new ContextKeyEqualsExpr(key, value); + } + + private constructor(private readonly key: string, private readonly value: any) { } public getType(): ContextKeyExprType { @@ -286,21 +315,7 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyDefinedExpr(this.key); - } - return new ContextKeyNotExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' == \'' + this.value + '\''; } @@ -311,10 +326,25 @@ export class ContextKeyEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyNotEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotEqualsExpr implements ContextKeyExpr { - constructor(private key: string, private value: any) { + + public static create(key: string, value: any): ContextKeyExpr { + if (typeof value === 'boolean') { + if (value) { + return ContextKeyNotExpr.create(key); + } + return ContextKeyDefinedExpr.create(key); + } + return new ContextKeyNotEqualsExpr(key, value); + } + + private constructor(private key: string, private value: any) { } public getType(): ContextKeyExprType { @@ -351,21 +381,7 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { /* tslint:enable:triple-equals */ } - public normalize(): ContextKeyExpr { - if (typeof this.value === 'boolean') { - if (this.value) { - return new ContextKeyNotExpr(this.key); - } - return new ContextKeyDefinedExpr(this.key); - } - return this; - } - public serialize(): string { - if (typeof this.value === 'boolean') { - return this.normalize().serialize(); - } - return this.key + ' != \'' + this.value + '\''; } @@ -376,10 +392,19 @@ export class ContextKeyNotEqualsExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNotEquals(this.key, this.value); } + + public negate(): ContextKeyExpr { + return ContextKeyEqualsExpr.create(this.key, this.value); + } } export class ContextKeyNotExpr implements ContextKeyExpr { - constructor(private key: string) { + + public static create(key: string): ContextKeyExpr { + return new ContextKeyNotExpr(key); + } + + private constructor(private key: string) { } public getType(): ContextKeyExprType { @@ -407,10 +432,6 @@ export class ContextKeyNotExpr implements ContextKeyExpr { return (!context.getValue(this.key)); } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { return '!' + this.key; } @@ -422,11 +443,19 @@ export class ContextKeyNotExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return mapFnc.mapNot(this.key); } + + public negate(): ContextKeyExpr { + return ContextKeyDefinedExpr.create(this.key); + } } export class ContextKeyRegexExpr implements ContextKeyExpr { - constructor(private key: string, private regexp: RegExp | null) { + public static create(key: string, regexp: RegExp | null): ContextKeyExpr { + return new ContextKeyRegexExpr(key, regexp); + } + + private constructor(private key: string, private regexp: RegExp | null) { // } @@ -466,10 +495,6 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return this.regexp ? this.regexp.test(value) : false; } - public normalize(): ContextKeyExpr { - return this; - } - public serialize(): string { const value = this.regexp ? `/${this.regexp.source}/${this.regexp.ignoreCase ? 'i' : ''}` @@ -481,22 +506,99 @@ export class ContextKeyRegexExpr implements ContextKeyExpr { return [this.key]; } - public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + public map(mapFnc: IContextKeyExprMapper): ContextKeyRegexExpr { return mapFnc.mapRegex(this.key, this.regexp); } + + public negate(): ContextKeyExpr { + return ContextKeyNotRegexExpr.create(this); + } +} + +export class ContextKeyNotRegexExpr implements ContextKeyExpr { + + public static create(actual: ContextKeyRegexExpr): ContextKeyExpr { + return new ContextKeyNotRegexExpr(actual); + } + + private constructor(private readonly _actual: ContextKeyRegexExpr) { + // + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.NotRegex; + } + + public cmp(other: ContextKeyNotRegexExpr): number { + return this._actual.cmp(other._actual); + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyNotRegexExpr) { + return this._actual.equals(other._actual); + } + return false; + } + + public evaluate(context: IContext): boolean { + return !this._actual.evaluate(context); + } + + public serialize(): string { + throw new Error('Method not implemented.'); + } + + public keys(): string[] { + return this._actual.keys(); + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyNotRegexExpr(this._actual.map(mapFnc)); + } + + public negate(): ContextKeyExpr { + return this._actual; + } } export class ContextKeyAndExpr implements ContextKeyExpr { - public readonly expr: ContextKeyExpr[]; - constructor(expr: Array) { - this.expr = ContextKeyAndExpr._normalizeArr(expr); + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyAndExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyAndExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { } public getType(): ContextKeyExprType { return ContextKeyExprType.And; } + public cmp(other: ContextKeyAndExpr): number { + if (this.expr.length < other.expr.length) { + return -1; + } + if (this.expr.length > other.expr.length) { + return 1; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + const r = cmp(this.expr[i], other.expr[i]); + if (r !== 0) { + return r; + } + } + return 0; + } + public equals(other: ContextKeyExpr): boolean { if (other instanceof ContextKeyAndExpr) { if (this.expr.length !== other.expr.length) { @@ -531,16 +633,16 @@ export class ContextKeyAndExpr implements ContextKeyExpr { continue; } - e = e.normalize(); - if (!e) { - continue; - } - if (e instanceof ContextKeyAndExpr) { expr = expr.concat(e.expr); continue; } + if (e instanceof ContextKeyOrExpr) { + // Not allowed, because we don't have parens! + throw new Error(`It is not allowed to have an or expression here due to lack of parens!`); + } + expr.push(e); } @@ -550,29 +652,7 @@ export class ContextKeyAndExpr implements ContextKeyExpr { return expr; } - public normalize(): ContextKeyExpr | undefined { - if (this.expr.length === 0) { - return undefined; - } - - if (this.expr.length === 1) { - return this.expr[0]; - } - - return this; - } - public serialize(): string { - if (this.expr.length === 0) { - return ''; - } - if (this.expr.length === 1) { - const normalized = this.normalize(); - if (!normalized) { - return ''; - } - return normalized.serialize(); - } return this.expr.map(e => e.serialize()).join(' && '); } @@ -587,6 +667,132 @@ export class ContextKeyAndExpr implements ContextKeyExpr { public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { return new ContextKeyAndExpr(this.expr.map(expr => expr.map(mapFnc))); } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + return ContextKeyOrExpr.create(result)!; + } +} + +export class ContextKeyOrExpr implements ContextKeyExpr { + + public static create(_expr: Array): ContextKeyExpr | undefined { + const expr = ContextKeyOrExpr._normalizeArr(_expr); + if (expr.length === 0) { + return undefined; + } + + if (expr.length === 1) { + return expr[0]; + } + + return new ContextKeyOrExpr(expr); + } + + private constructor(public readonly expr: ContextKeyExpr[]) { + } + + public getType(): ContextKeyExprType { + return ContextKeyExprType.Or; + } + + public equals(other: ContextKeyExpr): boolean { + if (other instanceof ContextKeyOrExpr) { + if (this.expr.length !== other.expr.length) { + return false; + } + for (let i = 0, len = this.expr.length; i < len; i++) { + if (!this.expr[i].equals(other.expr[i])) { + return false; + } + } + return true; + } + return false; + } + + public evaluate(context: IContext): boolean { + for (let i = 0, len = this.expr.length; i < len; i++) { + if (this.expr[i].evaluate(context)) { + return true; + } + } + return false; + } + + private static _normalizeArr(arr: Array): ContextKeyExpr[] { + let expr: ContextKeyExpr[] = []; + + if (arr) { + for (let i = 0, len = arr.length; i < len; i++) { + let e: ContextKeyExpr | null | undefined = arr[i]; + if (!e) { + continue; + } + + if (e instanceof ContextKeyOrExpr) { + expr = expr.concat(e.expr); + continue; + } + + expr.push(e); + } + + expr.sort(cmp); + } + + return expr; + } + + public serialize(): string { + return this.expr.map(e => e.serialize()).join(' || '); + } + + public keys(): string[] { + const result: string[] = []; + for (let expr of this.expr) { + result.push(...expr.keys()); + } + return result; + } + + public map(mapFnc: IContextKeyExprMapper): ContextKeyExpr { + return new ContextKeyOrExpr(this.expr.map(expr => expr.map(mapFnc))); + } + + public negate(): ContextKeyExpr { + let result: ContextKeyExpr[] = []; + for (let expr of this.expr) { + result.push(expr.negate()); + } + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; + } + return [node]; + }; + + // We don't support parens, so here we distribute the AND over the OR terminals + // We always take the first 2 AND pairs and distribute them + while (result.length > 1) { + const LEFT = result.shift()!; + const RIGHT = result.shift()!; + + const all: ContextKeyExpr[] = []; + for (const left of terminals(LEFT)) { + for (const right of terminals(RIGHT)) { + all.push(ContextKeyExpr.and(left, right)!); + } + } + result.unshift(ContextKeyExpr.or(...all)!); + } + + return result[0]; + } } // {{SQL CARBON EDIT}} @@ -621,6 +827,10 @@ export class ContextKeyGreaterThanEqualsExpr implements ContextKeyExpr { return false; } + public negate(): ContextKeyExpr { + throw new Error('Method not implemented.'); // @TODO anthonydresser need to figure out what to do in this case + } + public evaluate(context: IContext): boolean { const keyVal = context.getValue(this.key); if (!keyVal) { @@ -694,6 +904,10 @@ export class ContextKeyLessThanEqualsExpr implements ContextKeyExpr { return this; } + public negate(): ContextKeyExpr { + throw new Error('Method not implemented.'); // @TODO anthonydresser need to figure out what to do in this case + } + public serialize(): string { return this.key + ' <= \'' + this.value + '\''; } diff --git a/src/vs/platform/contextkey/test/common/contextkey.test.ts b/src/vs/platform/contextkey/test/common/contextkey.test.ts index 7d24eff42a..2b37b058c4 100644 --- a/src/vs/platform/contextkey/test/common/contextkey.test.ts +++ b/src/vs/platform/contextkey/test/common/contextkey.test.ts @@ -27,31 +27,28 @@ suite('ContextKeyExpr', () => { ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.not('d1'), ContextKeyExpr.not('d2'), - // {{SQL CARBON EDIT}} - ContextKeyExpr.greaterThanEquals('e1', 'ee1'), - ContextKeyExpr.greaterThanEquals('e2', 'ee2'), - ContextKeyExpr.lessThanEquals('f1', 'ff1'), - ContextKeyExpr.lessThanEquals('f2', 'ff2') - // - ); + ContextKeyExpr.greaterThanEquals('e1', 'ee1'), // {{SQL CARBON EDIT}} add test case + ContextKeyExpr.greaterThanEquals('e2', 'ee2'), // {{SQL CARBON EDIT}} add test case + ContextKeyExpr.lessThanEquals('f1', 'ff1'), // {{SQL CARBON EDIT}} add test case + ContextKeyExpr.lessThanEquals('f2', 'ff2'), // {{SQL CARBON EDIT}} add test case + )!; let b = ContextKeyExpr.and( - // {{SQL CARBON EDIT}} - ContextKeyExpr.greaterThanEquals('e2', 'ee2'), + ContextKeyExpr.lessThanEquals('f1', 'ff1'), // {{SQL CARBON EDIT}} + ContextKeyExpr.lessThanEquals('f2', 'ff2'), // {{SQL CARBON EDIT}} + ContextKeyExpr.greaterThanEquals('e2', 'ee2'), // {{SQL CARBON EDIT}} + ContextKeyExpr.greaterThanEquals('e1', 'ee1'), // {{SQL CARBON EDIT}} ContextKeyExpr.equals('b2', 'bb2'), ContextKeyExpr.notEquals('c1', 'cc1'), ContextKeyExpr.not('d1'), - ContextKeyExpr.lessThanEquals('f1', 'ff1'), ContextKeyExpr.regex('d4', /\*\*3*/), - ContextKeyExpr.greaterThanEquals('e1', 'ee1'), ContextKeyExpr.notEquals('c2', 'cc2'), ContextKeyExpr.has('a2'), ContextKeyExpr.equals('b1', 'bb1'), ContextKeyExpr.regex('d3', /d.*/), ContextKeyExpr.has('a1'), - ContextKeyExpr.lessThanEquals('f2', 'ff2'), ContextKeyExpr.and(ContextKeyExpr.equals('and.a', true)), ContextKeyExpr.not('d2') - ); + )!; assert(a.equals(b), 'expressions should be equal'); }); @@ -61,10 +58,10 @@ suite('ContextKeyExpr', () => { let key1IsFalse = ContextKeyExpr.equals('key1', false); let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - assert.ok(key1IsTrue.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsNotFalse.normalize()!.equals(ContextKeyExpr.has('key1'))); - assert.ok(key1IsFalse.normalize()!.equals(ContextKeyExpr.not('key1'))); - assert.ok(key1IsNotTrue.normalize()!.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsTrue.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsNotFalse.equals(ContextKeyExpr.has('key1'))); + assert.ok(key1IsFalse.equals(ContextKeyExpr.not('key1'))); + assert.ok(key1IsNotTrue.equals(ContextKeyExpr.not('key1'))); }); test('evaluate', () => { @@ -108,5 +105,24 @@ suite('ContextKeyExpr', () => { testExpression('a && !b && c == 5', true && !false && '5' == '5'); testExpression('d =~ /e.*/', false); /* tslint:enable:triple-equals */ + + // precedence test: false && true || true === true because && is evaluated first + testExpression('b && a || a', true); + + testExpression('a || b', true); + testExpression('b || b', false); + testExpression('b && a || a && b', false); + }); + + test('negate', () => { + function testNegate(expr: string, expected: string): void { + const actual = ContextKeyExpr.deserialize(expr)!.negate().serialize(); + assert.strictEqual(actual, expected); + } + testNegate('a', '!a'); + testNegate('a && b || c', '!a && !c || !b && !c'); + testNegate('a && b || c || d', '!a && !c && !d || !b && !c && !d'); + testNegate('!a && !b || !c && !d', 'a && c || a && d || b && c || b && d'); + testNegate('!a && !b || !c && !d || !e && !f', 'a && c && e || a && c && f || a && d && e || a && d && f || b && c && e || b && c && f || b && d && e || b && d && f'); }); }); diff --git a/src/vs/platform/driver/electron-browser/driver.ts b/src/vs/platform/driver/electron-browser/driver.ts index f5772d4296..920a1d19c8 100644 --- a/src/vs/platform/driver/electron-browser/driver.ts +++ b/src/vs/platform/driver/electron-browser/driver.ts @@ -206,7 +206,7 @@ class WindowDriver implements IWindowDriver { throw new Error(`Xterm not found: ${selector}`); } - xterm._core.handler(text); + xterm._core._coreService.triggerDataEvent(text); } async openDevTools(): Promise { diff --git a/src/vs/platform/environment/common/environment.ts b/src/vs/platform/environment/common/environment.ts index ad118ecd0f..c84fb693e8 100644 --- a/src/vs/platform/environment/common/environment.ts +++ b/src/vs/platform/environment/common/environment.ts @@ -47,6 +47,7 @@ export interface ParsedArgs { 'disable-extension'?: string | string[]; 'list-extensions'?: boolean; 'show-versions'?: boolean; + 'category'?: string; 'install-extension'?: string | string[]; 'uninstall-extension'?: string | string[]; 'locate-extension'?: string | string[]; diff --git a/src/vs/platform/environment/node/argv.ts b/src/vs/platform/environment/node/argv.ts index c21b270f6e..fb94ffa0ec 100644 --- a/src/vs/platform/environment/node/argv.ts +++ b/src/vs/platform/environment/node/argv.ts @@ -48,6 +48,7 @@ export const options: Option[] = [ { id: 'extensions-dir', type: 'string', deprecates: 'extensionHomePath', cat: 'e', args: 'dir', description: localize('extensionHomePath', "Set the root path for extensions.") }, { id: 'list-extensions', type: 'boolean', cat: 'e', description: localize('listExtensions', "List the installed extensions.") }, { id: 'show-versions', type: 'boolean', cat: 'e', description: localize('showVersions', "Show versions of installed extensions, when using --list-extension.") }, + { id: 'category', type: 'string', cat: 'e', description: localize('category', "Filters installed extensions by provided category, when using --list-extension.") }, { id: 'install-extension', type: 'string', cat: 'e', args: 'extension-id | path-to-vsix', description: localize('installExtension', "Installs or updates the extension. Use `--force` argument to avoid prompts.") }, { id: 'uninstall-extension', type: 'string', cat: 'e', args: 'extension-id', description: localize('uninstallExtension', "Uninstalls an extension.") }, { id: 'enable-proposed-api', type: 'string', cat: 'e', args: 'extension-id', description: localize('experimentalApis', "Enables proposed API features for extensions. Can receive one or more extension IDs to enable individually.") }, diff --git a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts index b90c6b9dd7..571f0c6513 100644 --- a/src/vs/platform/extensionManagement/common/extensionGalleryService.ts +++ b/src/vs/platform/extensionManagement/common/extensionGalleryService.ts @@ -27,6 +27,7 @@ import { joinPath } from 'vs/base/common/resources'; import { VSBuffer } from 'vs/base/common/buffer'; import { IProductService } from 'vs/platform/product/common/product'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; +import { optional } from 'vs/platform/instantiation/common/instantiation'; interface IRawGalleryExtensionFile { assetType: string; @@ -389,7 +390,7 @@ export class ExtensionGalleryService implements IExtensionGalleryService { @IConfigurationService private configurationService: IConfigurationService, @IFileService private readonly fileService: IFileService, @IProductService private readonly productService: IProductService, - @IStorageService private readonly storageService: IStorageService, + @optional(IStorageService) private readonly storageService: IStorageService, ) { const config = productService.extensionsGallery; this.extensionsGalleryUrl = config && config.serviceUrl; diff --git a/src/vs/platform/keybinding/common/keybindingResolver.ts b/src/vs/platform/keybinding/common/keybindingResolver.ts index 547e9ff777..5172a4052d 100644 --- a/src/vs/platform/keybinding/common/keybindingResolver.ts +++ b/src/vs/platform/keybinding/common/keybindingResolver.ts @@ -6,7 +6,7 @@ import { isNonEmptyArray } from 'vs/base/common/arrays'; import { MenuRegistry } from 'vs/platform/actions/common/actions'; import { CommandsRegistry, ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext, ContextKeyOrExpr } from 'vs/platform/contextkey/common/contextkey'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { keys } from 'vs/base/common/map'; @@ -171,7 +171,6 @@ export class KeybindingResolver { /** * Returns true if it is provable `a` implies `b`. - * **Precondition**: Assumes `a` and `b` are normalized! */ public static whenIsEntirelyIncluded(a: ContextKeyExpr | null | undefined, b: ContextKeyExpr | null | undefined): boolean { if (!b) { @@ -181,26 +180,35 @@ export class KeybindingResolver { return false; } - const aExpressions: ContextKeyExpr[] = ((a instanceof ContextKeyAndExpr) ? a.expr : [a]); - const bExpressions: ContextKeyExpr[] = ((b instanceof ContextKeyAndExpr) ? b.expr : [b]); + return this._implies(a, b); + } - let aIndex = 0; - for (const bExpr of bExpressions) { - let bExprMatched = false; - while (!bExprMatched && aIndex < aExpressions.length) { - let aExpr = aExpressions[aIndex]; - if (aExpr.equals(bExpr)) { - bExprMatched = true; - } - aIndex++; + /** + * Returns true if it is provable `p` implies `q`. + */ + private static _implies(p: ContextKeyExpr, q: ContextKeyExpr): boolean { + const notP = p.negate(); + + const terminals = (node: ContextKeyExpr) => { + if (node instanceof ContextKeyOrExpr) { + return node.expr; } + return [node]; + }; - if (!bExprMatched) { - return false; + let expr = terminals(notP).concat(terminals(q)); + for (let i = 0; i < expr.length; i++) { + const a = expr[i]; + const notA = a.negate(); + for (let j = i + 1; j < expr.length; j++) { + const b = expr[j]; + if (notA.equals(b)) { + return true; + } } } - return true; + return false; } public getDefaultBoundCommands(): Map { diff --git a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts index 69cc42f8ca..ddee4b60a8 100644 --- a/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts +++ b/src/vs/platform/keybinding/test/common/abstractKeybindingService.test.ts @@ -121,6 +121,7 @@ suite('AbstractKeybindingService', () => { let commandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand: (commandId: string, ...args: any[]): Promise => { executeCommandCalls.push({ commandId: commandId, diff --git a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts index baa17f0af5..9a61d91b4f 100644 --- a/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts +++ b/src/vs/platform/keybinding/test/common/keybindingResolver.test.ts @@ -5,7 +5,7 @@ import * as assert from 'assert'; import { KeyChord, KeyCode, KeyMod, SimpleKeybinding, createKeybinding, createSimpleKeybinding } from 'vs/base/common/keyCodes'; import { OS } from 'vs/base/common/platform'; -import { ContextKeyAndExpr, ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; +import { ContextKeyExpr, IContext } from 'vs/platform/contextkey/common/contextkey'; import { KeybindingResolver } from 'vs/platform/keybinding/common/keybindingResolver'; import { ResolvedKeybindingItem } from 'vs/platform/keybinding/common/resolvedKeybindingItem'; import { USLayoutResolvedKeybinding } from 'vs/platform/keybinding/common/usLayoutResolvedKeybinding'; @@ -20,13 +20,13 @@ function createContext(ctx: any) { suite('KeybindingResolver', () => { - function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr, isDefault: boolean): ResolvedKeybindingItem { + function kbItem(keybinding: number, command: string, commandArgs: any, when: ContextKeyExpr | undefined, isDefault: boolean): ResolvedKeybindingItem { const resolvedKeybinding = (keybinding !== 0 ? new USLayoutResolvedKeybinding(createKeybinding(keybinding, OS)!, OS) : undefined); return new ResolvedKeybindingItem( resolvedKeybinding, command, commandArgs, - when ? when.normalize() : undefined, + when, isDefault ); } @@ -191,64 +191,41 @@ suite('KeybindingResolver', () => { }); test('contextIsEntirelyIncluded', () => { - let assertIsIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), true); + const assertIsIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), true); }; - let assertIsNotIncluded = (a: ContextKeyExpr[], b: ContextKeyExpr[]) => { - let tmpA = new ContextKeyAndExpr(a).normalize(); - let tmpB = new ContextKeyAndExpr(b).normalize(); - assert.equal(KeybindingResolver.whenIsEntirelyIncluded(tmpA, tmpB), false); + const assertIsNotIncluded = (a: string | null, b: string | null) => { + assert.equal(KeybindingResolver.whenIsEntirelyIncluded(ContextKeyExpr.deserialize(a), ContextKeyExpr.deserialize(b)), false); }; - let key1IsTrue = ContextKeyExpr.equals('key1', true); - let key1IsNotFalse = ContextKeyExpr.notEquals('key1', false); - let key1IsFalse = ContextKeyExpr.equals('key1', false); - let key1IsNotTrue = ContextKeyExpr.notEquals('key1', true); - let key2IsTrue = ContextKeyExpr.equals('key2', true); - let key2IsNotFalse = ContextKeyExpr.notEquals('key2', false); - let key3IsTrue = ContextKeyExpr.equals('key3', true); - let key4IsTrue = ContextKeyExpr.equals('key4', true); - assertIsIncluded([key1IsTrue], null!); - assertIsIncluded([key1IsTrue], []); - assertIsIncluded([key1IsTrue], [key1IsTrue]); - assertIsIncluded([key1IsTrue], [key1IsNotFalse]); + assertIsIncluded('key1', null); + assertIsIncluded('key1', ''); + assertIsIncluded('key1', 'key1'); + assertIsIncluded('!key1', ''); + assertIsIncluded('!key1', '!key1'); + assertIsIncluded('key2', ''); + assertIsIncluded('key2', 'key2'); + assertIsIncluded('key1 && key1 && key2 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key2'); + assertIsIncluded('key1 && key2', 'key1'); + assertIsIncluded('key1 && key2', ''); + assertIsIncluded('key1', 'key1 || key2'); + assertIsIncluded('key1 || !key1', 'key2 || !key2'); + assertIsIncluded('key1', 'key1 || key2 && key3'); - assertIsIncluded([key1IsFalse], []); - assertIsIncluded([key1IsFalse], [key1IsFalse]); - assertIsIncluded([key1IsFalse], [key1IsNotTrue]); - - assertIsIncluded([key2IsNotFalse], []); - assertIsIncluded([key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key2IsNotFalse], [key2IsTrue]); - - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key2IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsTrue]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], [key1IsNotFalse]); - assertIsIncluded([key1IsTrue, key2IsNotFalse], []); - - assertIsNotIncluded([key1IsTrue], [key1IsFalse]); - assertIsNotIncluded([key1IsTrue], [key1IsNotTrue]); - assertIsNotIncluded([key1IsNotFalse], [key1IsFalse]); - assertIsNotIncluded([key1IsNotFalse], [key1IsNotTrue]); - - assertIsNotIncluded([key1IsFalse], [key1IsTrue]); - assertIsNotIncluded([key1IsFalse], [key1IsNotFalse]); - assertIsNotIncluded([key1IsNotTrue], [key1IsTrue]); - assertIsNotIncluded([key1IsNotTrue], [key1IsNotFalse]); - - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key3IsTrue]); - assertIsNotIncluded([key1IsTrue, key2IsNotFalse], [key4IsTrue]); - assertIsNotIncluded([key1IsTrue], [key2IsTrue]); - assertIsNotIncluded([], [key2IsTrue]); - assertIsNotIncluded(null!, [key2IsTrue]); + assertIsNotIncluded('key1', '!key1'); + assertIsNotIncluded('!key1', 'key1'); + assertIsNotIncluded('key1 && key2', 'key3'); + assertIsNotIncluded('key1 && key2', 'key4'); + assertIsNotIncluded('key1', 'key2'); + assertIsNotIncluded('key1 || key2', 'key2'); + assertIsNotIncluded('', 'key2'); + assertIsNotIncluded(null, 'key2'); }); test('resolve command', function () { - function _kbItem(keybinding: number, command: string, when: ContextKeyExpr): ResolvedKeybindingItem { + function _kbItem(keybinding: number, command: string, when: ContextKeyExpr | undefined): ResolvedKeybindingItem { return kbItem(keybinding, command, null, when, true); } diff --git a/src/vs/platform/list/browser/listService.ts b/src/vs/platform/list/browser/listService.ts index efd553c56b..eeafec7b3b 100644 --- a/src/vs/platform/list/browser/listService.ts +++ b/src/vs/platform/list/browser/listService.ts @@ -247,7 +247,7 @@ export class WorkbenchList extends List { constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: IListRenderer[], + renderers: IListRenderer[], options: IListOptions, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @@ -787,7 +787,7 @@ export class WorkbenchObjectTree, TFilterData = void> constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], options: IObjectTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, @IListService listService: IListService, @@ -813,7 +813,7 @@ export class WorkbenchDataTree extends DataTree, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], dataSource: IDataSource, options: IDataTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, @@ -840,7 +840,7 @@ export class WorkbenchAsyncDataTree extends Async constructor( container: HTMLElement, delegate: IListVirtualDelegate, - renderers: ITreeRenderer[], + renderers: ITreeRenderer[], dataSource: IAsyncDataSource, options: IAsyncDataTreeOptions, @IContextKeyService contextKeyService: IContextKeyService, diff --git a/src/vs/platform/markers/common/markers.ts b/src/vs/platform/markers/common/markers.ts index 77ddb65a58..60ef4306c7 100644 --- a/src/vs/platform/markers/common/markers.ts +++ b/src/vs/platform/markers/common/markers.ts @@ -39,6 +39,7 @@ export interface IRelatedInformation { export const enum MarkerTag { Unnecessary = 1, + Deprecated = 2 } export enum MarkerSeverity { diff --git a/src/vs/platform/product/common/product.ts b/src/vs/platform/product/common/product.ts index a14c7675b7..71e8fc69b8 100644 --- a/src/vs/platform/product/common/product.ts +++ b/src/vs/platform/product/common/product.ts @@ -73,10 +73,9 @@ export interface IProductConfiguration { readonly recommendationsUrl: string; }; extensionTips: { [id: string]: string; }; - // {{SQL CARBON EDIT}} - recommendedExtensions: string[]; - extensionImportantTips: { [id: string]: { name: string; pattern: string; }; }; - readonly exeBasedExtensionTips: { [id: string]: { friendlyName: string, windowsPath?: string, recommendations: readonly string[] }; }; + recommendedExtensions: string[]; // {{SQL CARBON EDIT}} + extensionImportantTips: { [id: string]: { name: string; pattern: string; isExtensionPack?: boolean }; }; + readonly exeBasedExtensionTips: { [id: string]: IExeBasedExtensionTip; }; readonly extensionKeywords: { [extension: string]: readonly string[]; }; readonly extensionAllowedBadgeProviders: readonly string[]; readonly extensionAllowedProposedApi: readonly string[]; @@ -125,6 +124,14 @@ export interface IProductConfiguration { readonly uiExtensions?: readonly string[]; } +export interface IExeBasedExtensionTip { + friendlyName: string; + windowsPath?: string; + recommendations: readonly string[]; + important?: boolean; + exeFriendlyName?: string; +} + export interface ISurveyData { surveyId: string; surveyUrl: string; diff --git a/src/vs/platform/remote/browser/browserSocketFactory.ts b/src/vs/platform/remote/browser/browserSocketFactory.ts new file mode 100644 index 0000000000..519e908154 --- /dev/null +++ b/src/vs/platform/remote/browser/browserSocketFactory.ts @@ -0,0 +1,146 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; +import { VSBuffer } from 'vs/base/common/buffer'; +import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; +import { Event, Emitter } from 'vs/base/common/event'; + +export interface IWebSocketFactory { + create(url: string): IWebSocket; +} + +export interface IWebSocket { + readonly onData: Event; + readonly onOpen: Event; + readonly onClose: Event; + readonly onError: Event; + + send(data: ArrayBuffer | ArrayBufferView): void; + close(): void; +} + +class BrowserWebSocket implements IWebSocket { + + private readonly _onData = new Emitter(); + public readonly onData = this._onData.event; + + public readonly onOpen: Event; + public readonly onClose: Event; + public readonly onError: Event; + + private readonly _socket: WebSocket; + private readonly _fileReader: FileReader; + private readonly _queue: Blob[]; + private _isReading: boolean; + + private readonly _socketMessageListener: (ev: MessageEvent) => void; + + constructor(socket: WebSocket) { + this._socket = socket; + this._fileReader = new FileReader(); + this._queue = []; + this._isReading = false; + + this._fileReader.onload = (event) => { + this._isReading = false; + const buff = (event.target).result; + + this._onData.fire(buff); + + if (this._queue.length > 0) { + enqueue(this._queue.shift()!); + } + }; + + const enqueue = (blob: Blob) => { + if (this._isReading) { + this._queue.push(blob); + return; + } + this._isReading = true; + this._fileReader.readAsArrayBuffer(blob); + }; + + this._socketMessageListener = (ev: MessageEvent) => { + enqueue(ev.data); + }; + this._socket.addEventListener('message', this._socketMessageListener); + + this.onOpen = Event.fromDOMEventEmitter(this._socket, 'open'); + this.onClose = Event.fromDOMEventEmitter(this._socket, 'close'); + this.onError = Event.fromDOMEventEmitter(this._socket, 'error'); + } + + send(data: ArrayBuffer | ArrayBufferView): void { + this._socket.send(data); + } + + close(): void { + this._socket.close(); + this._socket.removeEventListener('message', this._socketMessageListener); + } +} + +export const defaultWebSocketFactory = new class implements IWebSocketFactory { + create(url: string): IWebSocket { + return new BrowserWebSocket(new WebSocket(url)); + } +}; + +class BrowserSocket implements ISocket { + public readonly socket: IWebSocket; + + constructor(socket: IWebSocket) { + this.socket = socket; + } + + public dispose(): void { + this.socket.close(); + } + + public onData(listener: (e: VSBuffer) => void): IDisposable { + return this.socket.onData((data) => listener(VSBuffer.wrap(new Uint8Array(data)))); + } + + public onClose(listener: () => void): IDisposable { + return this.socket.onClose(listener); + } + + public onEnd(listener: () => void): IDisposable { + return Disposable.None; + } + + public write(buffer: VSBuffer): void { + this.socket.send(buffer.buffer); + } + + public end(): void { + this.socket.close(); + } + +} + + +export class BrowserSocketFactory implements ISocketFactory { + private readonly _webSocketFactory: IWebSocketFactory; + + constructor(webSocketFactory: IWebSocketFactory | null | undefined) { + this._webSocketFactory = webSocketFactory || defaultWebSocketFactory; + } + + connect(host: string, port: number, query: string, callback: IConnectCallback): void { + const socket = this._webSocketFactory.create(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); + const errorListener = socket.onError((err) => callback(err, undefined)); + socket.onOpen(() => { + errorListener.dispose(); + callback(undefined, new BrowserSocket(socket)); + }); + } +} + + + diff --git a/src/vs/platform/remote/browser/browserWebSocketFactory.ts b/src/vs/platform/remote/browser/browserWebSocketFactory.ts deleted file mode 100644 index bbb4187b38..0000000000 --- a/src/vs/platform/remote/browser/browserWebSocketFactory.ts +++ /dev/null @@ -1,89 +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 { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; -import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; -import { VSBuffer } from 'vs/base/common/buffer'; -import { IDisposable, Disposable } from 'vs/base/common/lifecycle'; -import { onUnexpectedError } from 'vs/base/common/errors'; - -class BrowserSocket implements ISocket { - public readonly socket: WebSocket; - - constructor(socket: WebSocket) { - this.socket = socket; - } - - public dispose(): void { - this.socket.close(); - } - - public onData(_listener: (e: VSBuffer) => void): IDisposable { - const fileReader = new FileReader(); - const queue: Blob[] = []; - let isReading = false; - fileReader.onload = function (event) { - isReading = false; - const buff = (event.target).result; - - try { - _listener(VSBuffer.wrap(new Uint8Array(buff))); - } catch (err) { - onUnexpectedError(err); - } - - if (queue.length > 0) { - enqueue(queue.shift()!); - } - }; - const enqueue = (blob: Blob) => { - if (isReading) { - queue.push(blob); - return; - } - isReading = true; - fileReader.readAsArrayBuffer(blob); - }; - const listener = (e: MessageEvent) => { - enqueue(e.data); - }; - this.socket.addEventListener('message', listener); - return { - dispose: () => this.socket.removeEventListener('message', listener) - }; - } - - public onClose(listener: () => void): IDisposable { - this.socket.addEventListener('close', listener); - return { - dispose: () => this.socket.removeEventListener('close', listener) - }; - } - - public onEnd(listener: () => void): IDisposable { - return Disposable.None; - } - - public write(buffer: VSBuffer): void { - this.socket.send(buffer.buffer); - } - - public end(): void { - this.socket.close(); - } - -} - -export const browserWebSocketFactory = new class implements IWebSocketFactory { - connect(host: string, port: number, query: string, callback: IConnectCallback): void { - const errorListener = (err: any) => callback(err, undefined); - const socket = new WebSocket(`ws://${host}:${port}/?${query}&skipWebSocketFrames=false`); - socket.onopen = function (event) { - socket.removeEventListener('error', errorListener); - callback(undefined, new BrowserSocket(socket)); - }; - socket.addEventListener('error', errorListener); - } -}; diff --git a/src/vs/platform/remote/common/remoteAgentConnection.ts b/src/vs/platform/remote/common/remoteAgentConnection.ts index 5ce67e163b..f9c49f51d8 100644 --- a/src/vs/platform/remote/common/remoteAgentConnection.ts +++ b/src/vs/platform/remote/common/remoteAgentConnection.ts @@ -57,7 +57,7 @@ interface ISimpleConnectionOptions { port: number; reconnectionToken: string; reconnectionProtocol: PersistentProtocol | null; - webSocketFactory: IWebSocketFactory; + socketFactory: ISocketFactory; signService: ISignService; } @@ -65,13 +65,13 @@ export interface IConnectCallback { (err: any | undefined, socket: ISocket | undefined): void; } -export interface IWebSocketFactory { +export interface ISocketFactory { connect(host: string, port: number, query: string, callback: IConnectCallback): void; } async function connectToRemoteExtensionHostAgent(options: ISimpleConnectionOptions, connectionType: ConnectionType, args: any | undefined): Promise { const protocol = await new Promise((c, e) => { - options.webSocketFactory.connect( + options.socketFactory.connect( options.host, options.port, `reconnectionToken=${options.reconnectionToken}&reconnection=${options.reconnectionProtocol ? 'true' : 'false'}`, @@ -202,7 +202,7 @@ async function doConnectRemoteAgentTunnel(options: ISimpleConnectionOptions, sta export interface IConnectionOptions { isBuilt: boolean; commit: string | undefined; - webSocketFactory: IWebSocketFactory; + socketFactory: ISocketFactory; addressProvider: IAddressProvider; signService: ISignService; } @@ -216,7 +216,7 @@ async function resolveConnectionOptions(options: IConnectionOptions, reconnectio port: port, reconnectionToken: reconnectionToken, reconnectionProtocol: reconnectionProtocol, - webSocketFactory: options.webSocketFactory, + socketFactory: options.socketFactory, signService: options.signService }; } diff --git a/src/vs/platform/remote/common/remoteHosts.ts b/src/vs/platform/remote/common/remoteHosts.ts index 4c5b419780..d6e2fe7e8b 100644 --- a/src/vs/platform/remote/common/remoteHosts.ts +++ b/src/vs/platform/remote/common/remoteHosts.ts @@ -10,4 +10,16 @@ export const REMOTE_HOST_SCHEME = Schemas.vscodeRemote; export function getRemoteAuthority(uri: URI): string | undefined { return uri.scheme === REMOTE_HOST_SCHEME ? uri.authority : undefined; +} + +export function getRemoteName(authority: string | undefined): string | undefined { + if (!authority) { + return undefined; + } + const pos = authority.indexOf('+'); + if (pos < 0) { + // funky? bad authority? + return authority; + } + return authority.substr(0, pos); } \ No newline at end of file diff --git a/src/vs/platform/remote/node/nodeWebSocketFactory.ts b/src/vs/platform/remote/node/nodeSocketFactory.ts similarity index 89% rename from src/vs/platform/remote/node/nodeWebSocketFactory.ts rename to src/vs/platform/remote/node/nodeSocketFactory.ts index d2f33c732d..6447c7201c 100644 --- a/src/vs/platform/remote/node/nodeWebSocketFactory.ts +++ b/src/vs/platform/remote/node/nodeSocketFactory.ts @@ -5,9 +5,9 @@ import * as net from 'net'; import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; -import { IWebSocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; +import { ISocketFactory, IConnectCallback } from 'vs/platform/remote/common/remoteAgentConnection'; -export const nodeWebSocketFactory = new class implements IWebSocketFactory { +export const nodeSocketFactory = new class implements ISocketFactory { connect(host: string, port: number, query: string, callback: IConnectCallback): void { const errorListener = (err: any) => callback(err, undefined); diff --git a/src/vs/platform/request/common/request.ts b/src/vs/platform/request/common/request.ts index e8e22eb8ba..75c7a2cd05 100644 --- a/src/vs/platform/request/common/request.ts +++ b/src/vs/platform/request/common/request.ts @@ -90,7 +90,7 @@ Registry.as(Extensions.Configuration) 'http.proxy': { type: 'string', pattern: '^https?://([^:]*(:[^@]*)?@)?([^:]+)(:\\d+)?/?$|^$', - description: localize('proxy', "The proxy setting to use. If not set will be taken from the http_proxy and https_proxy environment variables.") + markdownDescription: localize('proxy', "The proxy setting to use. If not set, will be inherited from the `http_proxy` and `https_proxy` environment variables.") }, 'http.proxyStrictSSL': { type: 'boolean', @@ -100,7 +100,7 @@ Registry.as(Extensions.Configuration) 'http.proxyAuthorization': { type: ['null', 'string'], default: null, - description: localize('proxyAuthorization', "The value to send as the 'Proxy-Authorization' header for every network request.") + markdownDescription: localize('proxyAuthorization', "The value to send as the `Proxy-Authorization` header for every network request.") }, 'http.proxySupport': { type: 'string', diff --git a/src/vs/platform/telemetry/common/gdprTypings.ts b/src/vs/platform/telemetry/common/gdprTypings.ts index c9066d7ebe..99ad178a3d 100644 --- a/src/vs/platform/telemetry/common/gdprTypings.ts +++ b/src/vs/platform/telemetry/common/gdprTypings.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ export interface IPropertyData { - classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData'; + classification: 'SystemMetaData' | 'CallstackOrException' | 'CustomerContent' | 'PublicNonPersonalData' | 'EndUserPseudonymizedInformation'; purpose: 'PerformanceAndHealth' | 'FeatureInsight' | 'BusinessInsight'; endpoint?: string; isMeasurement?: boolean; diff --git a/src/vs/platform/telemetry/common/telemetryService.ts b/src/vs/platform/telemetry/common/telemetryService.ts index d9493cfb1b..905cf74166 100644 --- a/src/vs/platform/telemetry/common/telemetryService.ts +++ b/src/vs/platform/telemetry/common/telemetryService.ts @@ -69,20 +69,16 @@ export class TelemetryService implements ITelemetryService { this._commonProperties.then(values => { const isHashedId = /^[a-f0-9]+$/i.test(values['common.machineId']); - /* __GDPR__ - "machineIdFallback" : { - "usingFallbackGuid" : { "classification": "SystemMetaData", "purpose": "BusinessInsight", "isMeasurement": true } - } - */ - this.publicLog('machineIdFallback', { usingFallbackGuid: !isHashedId }); + type MachineIdFallbackClassification = { + usingFallbackGuid: { classification: 'SystemMetaData', purpose: 'BusinessInsight', isMeasurement: true }; + }; + this.publicLog2<{ usingFallbackGuid: boolean }, MachineIdFallbackClassification>('machineIdFallback', { usingFallbackGuid: !isHashedId }); if (config.trueMachineId) { - /* __GDPR__ - "machineIdDisambiguation" : { - "correctedMachineId" : { "endPoint": "MacAddressHash", "classification": "EndUserPseudonymizedInformation", "purpose": "FeatureInsight" } - } - */ - this.publicLog('machineIdDisambiguation', { correctedMachineId: config.trueMachineId }); + type MachineIdDisambiguationClassification = { + correctedMachineId: { endPoint: 'MacAddressHash', classification: 'EndUserPseudonymizedInformation', purpose: 'FeatureInsight' }; + }; + this.publicLog2<{ correctedMachineId: string }, MachineIdDisambiguationClassification>('machineIdDisambiguation', { correctedMachineId: config.trueMachineId }); } }); } diff --git a/src/vs/platform/telemetry/common/telemetryUtils.ts b/src/vs/platform/telemetry/common/telemetryUtils.ts index 04066a752b..a948ff65ee 100644 --- a/src/vs/platform/telemetry/common/telemetryUtils.ts +++ b/src/vs/platform/telemetry/common/telemetryUtils.ts @@ -33,17 +33,17 @@ export const NullTelemetryService = new class implements ITelemetryService { export interface ITelemetryAppender { log(eventName: string, data: any): void; - dispose(): Promise | undefined; + flush(): Promise; } export function combinedAppender(...appenders: ITelemetryAppender[]): ITelemetryAppender { return { log: (e, d) => appenders.forEach(a => a.log(e, d)), - dispose: () => Promise.all(appenders.map(a => a.dispose())) + flush: () => Promise.all(appenders.map(a => a.flush())) }; } -export const NullAppender: ITelemetryAppender = { log: () => null, dispose: () => Promise.resolve(null) }; +export const NullAppender: ITelemetryAppender = { log: () => null, flush: () => Promise.resolve(null) }; export class LogAppender implements ITelemetryAppender { @@ -51,7 +51,7 @@ export class LogAppender implements ITelemetryAppender { private commonPropertiesRegex = /^sessionID$|^version$|^timestamp$|^commitHash$|^common\./; constructor(@ILogService private readonly _logService: ILogService) { } - dispose(): Promise { + flush(): Promise { return Promise.resolve(undefined); } diff --git a/src/vs/platform/telemetry/node/appInsightsAppender.ts b/src/vs/platform/telemetry/node/appInsightsAppender.ts index a3a3bd7003..2954780b44 100644 --- a/src/vs/platform/telemetry/node/appInsightsAppender.ts +++ b/src/vs/platform/telemetry/node/appInsightsAppender.ts @@ -73,7 +73,7 @@ export class AppInsightsAppender implements ITelemetryAppender { }); } - dispose(): Promise | undefined { + flush(): Promise | undefined { if (this._aiClient) { return new Promise(resolve => { this._aiClient!.flush({ diff --git a/src/vs/platform/telemetry/node/telemetryIpc.ts b/src/vs/platform/telemetry/node/telemetryIpc.ts index 2c7b654606..b8b4d73c57 100644 --- a/src/vs/platform/telemetry/node/telemetryIpc.ts +++ b/src/vs/platform/telemetry/node/telemetryIpc.ts @@ -37,7 +37,7 @@ export class TelemetryAppenderClient implements ITelemetryAppender { return Promise.resolve(null); } - dispose(): any { + flush(): any { // TODO } } diff --git a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts index bead3fda58..4acef1165a 100644 --- a/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/appInsightsAppender.test.ts @@ -84,7 +84,7 @@ suite('AIAdapter', () => { }); teardown(() => { - adapter.dispose(); + adapter.flush(); }); test('Simple event', () => { diff --git a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts index 9ad9bd2bcb..cf4a45607f 100644 --- a/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts +++ b/src/vs/platform/telemetry/test/electron-browser/telemetryService.test.ts @@ -30,7 +30,7 @@ class TestTelemetryAppender implements ITelemetryAppender { return this.events.length; } - public dispose(): Promise { + public flush(): Promise { this.isDisposed = true; return Promise.resolve(null); } diff --git a/src/vs/platform/update/electron-main/updateService.win32.ts b/src/vs/platform/update/electron-main/updateService.win32.ts index 98d37398a6..2dcabb8387 100644 --- a/src/vs/platform/update/electron-main/updateService.win32.ts +++ b/src/vs/platform/update/electron-main/updateService.win32.ts @@ -115,12 +115,7 @@ export class Win32UpdateService extends AbstractUpdateService { const updateType = getUpdateType(); if (!update || !update.url || !update.version || !update.productVersion) { - /* __GDPR__ - "update:notAvailable" : { - "explicit" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ - this.telemetryService.publicLog('update:notAvailable', { explicit: !!context }); + this.telemetryService.publicLog2<{ explicit: boolean }, UpdateNotAvailableClassification>('update:notAvailable', { explicit: !!context }); this.setState(State.Idle(updateType)); return Promise.resolve(null); diff --git a/src/vs/vscode.proposed.d.ts b/src/vs/vscode.proposed.d.ts index b39f4b1c89..a4f1191dfe 100644 --- a/src/vs/vscode.proposed.d.ts +++ b/src/vs/vscode.proposed.d.ts @@ -565,6 +565,22 @@ declare module 'vscode' { //#endregion + //#region Joh: onDidExecuteCommand + + export interface CommandExecutionEvent { + command: string; + arguments: any[]; + } + + export namespace commands { + /** + * An event that is emitted when a [command](#Command) is executed. + */ + export const onDidExecuteCommand: Event; + } + + //#endregion + //#region Joh: decorations //todo@joh -> make class @@ -800,7 +816,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText) is triggered that will fire the * [TerminalRenderer.onDidAcceptInput](#TerminalRenderer.onDidAcceptInput) event. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Create a terminal renderer, show it and write hello world in red * ```typescript @@ -812,7 +828,7 @@ declare module 'vscode' { export interface TerminalRenderer { /** * The name of the terminal, this will appear in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ name: string; @@ -821,7 +837,7 @@ declare module 'vscode' { * a value smaller than the maximum value, if this is undefined the terminal will auto fit * to the maximum value [maximumDimensions](TerminalRenderer.maximumDimensions). * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Override the dimensions of a TerminalRenderer to 20 columns and 10 rows * ```typescript @@ -839,14 +855,14 @@ declare module 'vscode' { * Listen to [onDidChangeMaximumDimensions](TerminalRenderer.onDidChangeMaximumDimensions) * to get notified when this value changes. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly maximumDimensions: TerminalDimensions | undefined; /** * The corresponding [Terminal](#Terminal) for this TerminalRenderer. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly terminal: Terminal; @@ -855,7 +871,7 @@ declare module 'vscode' { * text to the underlying _process_, this will write the text to the terminal itself. * * @param text The text to write. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Write red text to the terminal * ```typescript @@ -874,7 +890,7 @@ declare module 'vscode' { * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their * corresponding VT sequence representation. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. * * **Example:** Simulate interaction with the terminal from an outside extension or a * workbench command such as `workbench.action.terminal.runSelectedText` @@ -892,7 +908,7 @@ declare module 'vscode' { * An event which fires when the [maximum dimensions](#TerminalRenderer.maximumDimensions) of * the terminal renderer change. * - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ readonly onDidChangeMaximumDimensions: Event; } @@ -902,60 +918,60 @@ declare module 'vscode' { * Create a [TerminalRenderer](#TerminalRenderer). * * @param name The name of the terminal renderer, this shows up in the terminal selector. - * @deprecated Use [virtual processes](#TerminalVirtualProcess) instead. + * @deprecated Use [ExtensionTerminalOptions](#ExtensionTerminalOptions) instead. */ export function createTerminalRenderer(name: string): TerminalRenderer; } //#endregion - //#region Terminal virtual process + //#region Extension terminals export namespace window { /** - * Creates a [Terminal](#Terminal) where an extension acts as the process. + * Creates a [Terminal](#Terminal) where an extension controls the teerminal. * - * @param options A [TerminalVirtualProcessOptions](#TerminalVirtualProcessOptions) object describing the - * characteristics of the new terminal. + * @param options An [ExtensionTerminalOptions](#ExtensionTerminalOptions) object describing + * the characteristics of the new terminal. * @return A new Terminal. */ - export function createTerminal(options: TerminalVirtualProcessOptions): Terminal; + export function createTerminal(options: ExtensionTerminalOptions): Terminal; } /** * Value-object describing what options a virtual process terminal should use. */ - export interface TerminalVirtualProcessOptions { + export interface ExtensionTerminalOptions { /** * A human-readable string which will be used to represent the terminal in the UI. */ name: string; /** - * An implementation of [TerminalVirtualProcess](#TerminalVirtualProcess) that allows an - * extension to act as a terminal's backing process. + * An implementation of [Pseudoterminal](#Pseudoterminal) that allows an extension to + * control a terminal. */ - virtualProcess: TerminalVirtualProcess; + pty: Pseudoterminal; } /** - * Defines the interface of a terminal virtual process, enabling extensions to act as a process - * in the terminal. + * Defines the interface of a terminal pty, enabling extensions to control a terminal. */ - interface TerminalVirtualProcess { + interface Pseudoterminal { /** * An event that when fired will write data to the terminal. Unlike - * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_, - * this will write the text to the terminal itself. + * [Terminal.sendText](#Terminal.sendText) which sends text to the underlying _process_ + * (the pty "slave"), this will write the text to the terminal itself (the pty "master"). * * **Example:** Write red text to the terminal * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { - * onDidWrite: writeEmitter.event + * const pty: vscode.Pseudoterminal = { + * onDidWrite: writeEmitter.event, + * open: () => writeEmitter.fire('\x1b[31mHello world\x1b[0m'), + * close: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * writeEmitter.fire('\x1b[31mHello world\x1b[0m'); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` * * **Example:** Move the cursor to the 10th row and 20th column and write an asterisk @@ -969,58 +985,82 @@ declare module 'vscode' { * An event that when fired allows overriding the [dimensions](#Terminal.dimensions) of the * terminal. Note that when set the overridden dimensions will only take effect when they * are lower than the actual dimensions of the terminal (ie. there will never be a scroll - * bar). Set to `undefined` for the terminal to go back to the regular dimensions. + * bar). Set to `undefined` for the terminal to go back to the regular dimensions (fit to + * the size of the panel). * * **Example:** Override the dimensions of a terminal to 20 columns and 10 rows * ```typescript * const dimensionsEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * onDidOverrideDimensions: dimensionsEmitter.event + * onDidOverrideDimensions: dimensionsEmitter.event, + * open: () => { + * dimensionsEmitter.fire({ + * columns: 20, + * rows: 10 + * }); + * }, + * close: () => {} * }; - * vscode.window.createTerminal({ name: 'My terminal', virtualProcess }); - * dimensionsEmitter.fire({ - * columns: 20, - * rows: 10 - * }); + * vscode.window.createTerminal({ name: 'My terminal', pty }); * ``` */ onDidOverrideDimensions?: Event; /** - * An event that when fired will exit the process with an exit code, this will behave the - * same for a virtual process as when a regular process exits with an exit code. Note that - * exit codes must be positive numbers, when negative the exit code will be forced to `1`. + * An event that when fired will signal that the pty is closed and dispose of the terminal. * - * **Example:** Exit with an exit code of `0` if the y key is pressed, otherwise `1`. + * **Example:** Exit the terminal when "y" is pressed, otherwise show a notification. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const exitEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const closeEmitter = new vscode.EventEmitter(); + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, - * input: data => exitEmitter.fire(data === 'y' ? 0 : 1) + * onDidClose: closeEmitter.event, + * open: () => writeEmitter.fire('Press y to exit successfully'), + * close: () => {} + * handleInput: { + * if (data !== 'y') { + * vscode.window.showInformationMessage('Something went wrong'); + * } + * data => closeEmitter.fire(); + * } * }; - * vscode.window.createTerminal({ name: 'Exit example', virtualProcess }); - * writeEmitter.fire('Press y to exit successfully'); + * vscode.window.createTerminal({ name: 'Exit example', pty }); */ - onDidExit?: Event; + onDidClose?: Event; /** - * Implement to handle keystrokes in the terminal or when an extension calls - * [Terminal.sendText](#Terminal.sendText). Keystrokes are converted into their - * corresponding VT sequence representation. + * Implement to handle when the pty is open and ready to start firing events. * - * @param data The sent data. + * @param initialDimensions The dimensions of the terminal, this will be undefined if the + * terminal panel has not been opened before this is called. + */ + open(initialDimensions: TerminalDimensions | undefined): void; + + /** + * Implement to handle when the terminal is closed by an act of the user. + */ + close(): void; + + /** + * Implement to handle incoming keystrokes in the terminal or when an extension calls + * [Terminal.sendText](#Terminal.sendText). `data` contains the keystrokes/text serialized into + * their corresponding VT sequence representation. + * + * @param data The incoming data. * * **Example:** Echo input in the terminal. The sequence for enter (`\r`) is translated to * CRLF to go to a new line and move the cursor to the start of the line. * ```typescript * const writeEmitter = new vscode.EventEmitter(); - * const virtualProcess: TerminalVirtualProcess = { + * const pty: vscode.Pseudoterminal = { * onDidWrite: writeEmitter.event, + * open: () => {}, + * close: () => {}, * handleInput: data => writeEmitter.fire(data === '\r' ? '\r\n' : data) * }; - * vscode.window.createTerminal({ name: 'Local echo', virtualProcess }); + * vscode.window.createTerminal({ name: 'Local echo', pty }); * ``` */ handleInput?(data: string): void; @@ -1034,19 +1074,6 @@ declare module 'vscode' { * @param dimensions The new dimensions. */ setDimensions?(dimensions: TerminalDimensions): void; - - /** - * Implement to handle when the terminal shuts down by an act of the user. - */ - shutdown?(): void; - - /** - * Implement to handle when the terminal is ready to start firing events. - * - * @param initialDimensions The dimensions of the terminal, this will be undefined if the - * terminal panel has not been opened before this is called. - */ - start?(initialDimensions: TerminalDimensions | undefined): void; } //#endregion @@ -1129,6 +1156,7 @@ declare module 'vscode' { } //#endregion + //#region CustomExecution /** * Class used to execute an extension callback as a task. */ @@ -1152,16 +1180,17 @@ declare module 'vscode' { */ export class CustomExecution2 { /** - * @param process The [TerminalVirtualProcess](#TerminalVirtualProcess) to be used by the task to display output. + * @param process The [Pseudotrminal](#Pseudoterminal) to be used by the task to display output. * @param callback The callback that will be called when the task is started by a user. */ - constructor(callback: (thisArg?: any) => Thenable); + constructor(callback: (thisArg?: any) => Thenable); /** - * The callback used to execute the task. Cancellation should be handled using the shutdown method of [TerminalVirtualProcess](#TerminalVirtualProcess). - * When the task is complete, onDidExit should be fired on the TerminalVirtualProcess with the exit code with '0' for success and a non-zero value for failure. + * The callback used to execute the task. Cancellation should be handled using + * [Pseudoterminal.close](#Pseudoterminal.close). When the task is complete fire + * [Pseudoterminal.onDidClose](#Pseudoterminal.onDidClose). */ - callback: (thisArg?: any) => Thenable; + callback: (thisArg?: any) => Thenable; } /** @@ -1187,6 +1216,7 @@ declare module 'vscode' { */ execution2?: ProcessExecution | ShellExecution | CustomExecution | CustomExecution2; } + //#endregion //#region Tasks export interface TaskPresentationOptions { @@ -1274,4 +1304,17 @@ declare module 'vscode' { } //#endregion + + //#region Deprecated support + + export enum DiagnosticTag { + /** + * Deprecated or obsolete code. + * + * Diagnostics with this tag are rendered with a strike through. + */ + Deprecated = 2, + } + + //#endregion } diff --git a/src/vs/workbench/api/browser/mainThreadCommands.ts b/src/vs/workbench/api/browser/mainThreadCommands.ts index e6e86b909f..81aa57e579 100644 --- a/src/vs/workbench/api/browser/mainThreadCommands.ts +++ b/src/vs/workbench/api/browser/mainThreadCommands.ts @@ -15,6 +15,7 @@ export class MainThreadCommands implements MainThreadCommandsShape { private readonly _commandRegistrations = new Map(); private readonly _generateCommandsDocumentationRegistration: IDisposable; private readonly _proxy: ExtHostCommandsShape; + private _onDidExecuteCommandListener?: IDisposable; constructor( extHostContext: IExtHostContext, @@ -77,6 +78,19 @@ export class MainThreadCommands implements MainThreadCommandsShape { return this._commandService.executeCommand(id, ...args); } + $registerCommandListener() { + if (!this._onDidExecuteCommandListener) { + this._onDidExecuteCommandListener = this._commandService.onDidExecuteCommand(command => this._proxy.$handleDidExecuteCommand(command)); + } + } + + $unregisterCommandListener() { + if (this._onDidExecuteCommandListener) { + this._onDidExecuteCommandListener.dispose(); + this._onDidExecuteCommandListener = undefined; + } + } + $getCommands(): Promise { return Promise.resolve([...CommandsRegistry.getCommands().keys()]); } diff --git a/src/vs/workbench/api/browser/mainThreadDebugService.ts b/src/vs/workbench/api/browser/mainThreadDebugService.ts index c68b1d3c91..c00cecd7a9 100644 --- a/src/vs/workbench/api/browser/mainThreadDebugService.ts +++ b/src/vs/workbench/api/browser/mainThreadDebugService.ts @@ -5,7 +5,7 @@ import { DisposableStore } from 'vs/base/common/lifecycle'; import { URI as uri } from 'vs/base/common/uri'; -import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, ITerminalSettings, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugService, IConfig, IDebugConfigurationProvider, IBreakpoint, IFunctionBreakpoint, IBreakpointData, IDebugAdapter, IDebugAdapterDescriptorFactory, IDebugSession, IDebugAdapterFactory } from 'vs/workbench/contrib/debug/common/debug'; import { ExtHostContext, ExtHostDebugServiceShape, MainThreadDebugServiceShape, DebugSessionUUID, MainContext, IExtHostContext, IBreakpointsDeltaDto, ISourceMultiBreakpointDto, ISourceBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto @@ -71,8 +71,8 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb return Promise.resolve(this._proxy.$substituteVariables(folder ? folder.uri : undefined, config)); } - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { - return Promise.resolve(this._proxy.$runInTerminal(args, config)); + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { + return Promise.resolve(this._proxy.$runInTerminal(args)); } // RPC methods (MainThreadDebugServiceShape) diff --git a/src/vs/workbench/api/browser/mainThreadTerminalService.ts b/src/vs/workbench/api/browser/mainThreadTerminalService.ts index 8aeaaf6144..d4e6c1f136 100644 --- a/src/vs/workbench/api/browser/mainThreadTerminalService.ts +++ b/src/vs/workbench/api/browser/mainThreadTerminalService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, ITerminalDimensions, EXT_HOST_CREATION_DELAY, IAvailableShellsRequest, IDefaultShellAndArgsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtHostContext, ExtHostTerminalServiceShape, MainThreadTerminalServiceShape, MainContext, IExtHostContext, ShellLaunchConfigDto, TerminalLaunchConfig, ITerminalDimensionsDto } from 'vs/workbench/api/common/extHost.protocol'; import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers'; import { URI } from 'vs/base/common/uri'; @@ -35,8 +35,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape // ITerminalService listeners this._toDispose.add(_terminalService.onInstanceCreated((instance) => { // Delay this message so the TerminalInstance constructor has a chance to finish and - // return the ID normally to the extension host. The ID that is passed here will be used - // to register non-extension API terminals in the extension host. + // return the ID normally to the extension host. The ID that is passed here will be + // used to register non-extension API terminals in the extension host. setTimeout(() => { this._onTerminalOpened(instance); this._onInstanceDimensionsChanged(instance); @@ -47,8 +47,8 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._toDispose.add(_terminalService.onInstanceProcessIdReady(instance => this._onTerminalProcessIdReady(instance))); this._toDispose.add(_terminalService.onInstanceDimensionsChanged(instance => this._onInstanceDimensionsChanged(instance))); this._toDispose.add(_terminalService.onInstanceMaximumDimensionsChanged(instance => this._onInstanceMaximumDimensionsChanged(instance))); - this._toDispose.add(_terminalService.onInstanceRequestExtHostProcess(request => this._onTerminalRequestExtHostProcess(request))); - this._toDispose.add(_terminalService.onInstanceRequestVirtualProcess(e => this._onTerminalRequestVirtualProcess(e))); + this._toDispose.add(_terminalService.onInstanceRequestSpawnExtHostProcess(request => this._onRequestSpawnExtHostProcess(request))); + this._toDispose.add(_terminalService.onInstanceRequestStartExtensionTerminal(e => this._onRequestStartExtensionTerminal(e))); this._toDispose.add(_terminalService.onActiveInstanceChanged(instance => this._onActiveTerminalChanged(instance ? instance.id : null))); this._toDispose.add(_terminalService.onInstanceTitleChanged(instance => this._onTitleChanged(instance.id, instance.title))); this._toDispose.add(_terminalService.configHelper.onWorkspacePermissionsChanged(isAllowed => this._onWorkspacePermissionsChanged(isAllowed))); @@ -90,7 +90,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape env: launchConfig.env, strictEnv: launchConfig.strictEnv, hideFromUser: launchConfig.hideFromUser, - isVirtualProcess: launchConfig.isVirtualProcess + isExtensionTerminal: launchConfig.isExtensionTerminal }; const terminal = this._terminalService.createTerminal(shellLaunchConfig); this._terminalProcesses.set(terminal.id, new Promise(r => this._terminalProcessesReady.set(terminal.id, r))); @@ -240,7 +240,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._proxy.$acceptTerminalMaximumDimensions(instance.id, instance.maxCols, instance.maxRows); } - private _onTerminalRequestExtHostProcess(request: ITerminalProcessExtHostRequest): void { + private _onRequestSpawnExtHostProcess(request: ISpawnExtHostProcessRequest): void { // Only allow processes on remote ext hosts if (!this._remoteAuthority) { return; @@ -261,7 +261,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape cwd: request.shellLaunchConfig.cwd, env: request.shellLaunchConfig.env }; - this._proxy.$createProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); + this._proxy.$spawnExtHostProcess(proxy.terminalId, shellLaunchConfigDto, request.activeWorkspaceRootUri, request.cols, request.rows, request.isWorkspaceShellAllowed); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); proxy.onResize(dimensions => this._proxy.$acceptProcessResize(proxy.terminalId, dimensions.cols, dimensions.rows)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); @@ -270,7 +270,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape proxy.onRequestLatency(() => this._onRequestLatency(proxy.terminalId)); } - private _onTerminalRequestVirtualProcess(request: ITerminalVirtualProcessRequest): void { + private _onRequestStartExtensionTerminal(request: IStartExtensionTerminalRequest): void { const proxy = request.proxy; const ready = this._terminalProcessesReady.get(proxy.terminalId); if (!ready) { @@ -286,7 +286,7 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape columns: request.cols, rows: request.rows } : undefined; - this._proxy.$startVirtualProcess(proxy.terminalId, initialDimensions); + this._proxy.$startExtensionTerminal(proxy.terminalId, initialDimensions); proxy.onInput(data => this._proxy.$acceptProcessInput(proxy.terminalId, data)); proxy.onShutdown(immediate => this._proxy.$acceptProcessShutdown(proxy.terminalId, immediate)); proxy.onRequestCwd(() => this._proxy.$acceptProcessRequestCwd(proxy.terminalId)); @@ -323,6 +323,13 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape this._getTerminalProcess(terminalId).then(e => e.emitCwd(cwd)); } + public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void { + const instance = this._terminalService.getInstanceFromId(terminalId); + if (instance) { + this._getTerminalProcess(terminalId).then(e => e.emitResolvedShellLaunchConfig(shellLaunchConfig)); + } + } + private async _onRequestLatency(terminalId: number): Promise { const COUNT = 2; let sum = 0; diff --git a/src/vs/workbench/api/browser/mainThreadWorkspace.ts b/src/vs/workbench/api/browser/mainThreadWorkspace.ts index 88afe28b97..f21fa19000 100644 --- a/src/vs/workbench/api/browser/mainThreadWorkspace.ts +++ b/src/vs/workbench/api/browser/mainThreadWorkspace.ts @@ -24,6 +24,7 @@ import { ExtHostContext, ExtHostWorkspaceShape, IExtHostContext, MainContext, Ma import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { isEqualOrParent } from 'vs/base/common/resources'; import { INotificationService } from 'vs/platform/notification/common/notification'; +import { withNullAsUndefined } from 'vs/base/common/types'; @extHostNamedCustomer(MainContext.MainThreadWorkspace) export class MainThreadWorkspace implements MainThreadWorkspaceShape { @@ -122,21 +123,21 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape { // --- search --- - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string | null, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise { const includeFolder = URI.revive(_includeFolder); const workspace = this._contextService.getWorkspace(); if (!workspace.folders.length) { - return Promise.resolve(undefined); + return Promise.resolve(null); } const query = this._queryBuilder.file( includeFolder ? [includeFolder] : workspace.folders.map(f => f.uri), { - maxResults, + maxResults: withNullAsUndefined(maxResults), disregardExcludeSettings: (excludePatternOrDisregardExcludes === false) || undefined, disregardSearchExcludeSettings: true, disregardIgnoreFiles: true, - includePattern, + includePattern: withNullAsUndefined(includePattern), excludePattern: typeof excludePatternOrDisregardExcludes === 'string' ? excludePatternOrDisregardExcludes : undefined, _reason: 'startFileSearch' }); diff --git a/src/vs/workbench/api/common/extHost.protocol.ts b/src/vs/workbench/api/common/extHost.protocol.ts index a7e96e337e..9d3c1c4b84 100644 --- a/src/vs/workbench/api/common/extHost.protocol.ts +++ b/src/vs/workbench/api/common/extHost.protocol.ts @@ -21,7 +21,7 @@ import { EndOfLineSequence, ISingleEditOperation } from 'vs/editor/common/model' import { IModelChangedEvent } from 'vs/editor/common/model/mirrorTextModel'; import * as modes from 'vs/editor/common/modes'; import { CharacterPair, CommentRule, EnterAction } from 'vs/editor/common/modes/languageConfiguration'; -import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; +import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands'; import { ConfigurationTarget, IConfigurationData, IConfigurationModel } from 'vs/platform/configuration/common/configuration'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; @@ -40,9 +40,9 @@ import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor'; import * as tasks from 'vs/workbench/api/common/shared/tasks'; import { IRevealOptions, ITreeItem } from 'vs/workbench/common/views'; import * as callHierarchy from 'vs/workbench/contrib/callHierarchy/common/callHierarchy'; -import { IAdapterDescriptor, IConfig, ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; +import { IAdapterDescriptor, IConfig } from 'vs/workbench/contrib/debug/common/debug'; import { ITextQueryBuilderOptions } from 'vs/workbench/contrib/search/common/queryBuilder'; -import { ITerminalDimensions } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalDimensions, IShellLaunchConfig } from 'vs/workbench/contrib/terminal/common/terminal'; import { ExtensionActivationError } from 'vs/workbench/services/extensions/common/extensions'; import { createExtHostContextProxyIdentifier as createExtId, createMainContextProxyIdentifier as createMainId, IRPCProtocol } from 'vs/workbench/services/extensions/common/proxyIdentifier'; import * as search from 'vs/workbench/services/search/common/search'; @@ -118,6 +118,8 @@ export interface MainThreadClipboardShape extends IDisposable { export interface MainThreadCommandsShape extends IDisposable { $registerCommand(id: string): void; + $registerCommandListener(): void; + $unregisterCommandListener(): void; $unregisterCommand(id: string): void; $executeCommand(id: string, args: any[]): Promise; $getCommands(): Promise; @@ -391,7 +393,7 @@ export interface TerminalLaunchConfig { waitOnExit?: boolean; strictEnv?: boolean; hideFromUser?: boolean; - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; } export interface MainThreadTerminalServiceShape extends IDisposable { @@ -408,9 +410,10 @@ export interface MainThreadTerminalServiceShape extends IDisposable { $sendProcessData(terminalId: number, data: string): void; $sendProcessReady(terminalId: number, pid: number, cwd: string): void; $sendProcessExit(terminalId: number, exitCode: number): void; - $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void; $sendProcessInitialCwd(terminalId: number, cwd: string): void; $sendProcessCwd(terminalId: number, initialCwd: string): void; + $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void; + $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void; // Renderer $terminalRendererSetName(terminalId: number, name: string): void; @@ -582,7 +585,7 @@ export interface ITextSearchComplete { } export interface MainThreadWorkspaceShape extends IDisposable { - $startFileSearch(includePattern: string | undefined, includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false | undefined, maxResults: number | undefined, token: CancellationToken): Promise; + $startFileSearch(includePattern: string | null, includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false | null, maxResults: number | null, token: CancellationToken): Promise; $startTextSearch(query: search.IPatternInfo, options: ITextQueryBuilderOptions, requestId: number, token: CancellationToken): Promise; $checkExists(folders: UriComponents[], includes: string[], token: CancellationToken): Promise; $saveAll(includeUntitled?: boolean): Promise; @@ -739,6 +742,7 @@ export interface MainThreadWindowShape extends IDisposable { export interface ExtHostCommandsShape { $executeContributedCommand(id: string, ...args: any[]): Promise; $getContributedCommandHandlerDescriptions(): Promise<{ [id: string]: string | ICommandHandlerDescription }>; + $handleDidExecuteCommand(command: ICommandEvent): void; } export interface ExtHostConfigurationShape { @@ -1161,8 +1165,8 @@ export interface ExtHostTerminalServiceShape { $acceptTerminalTitleChange(id: number, name: string): void; $acceptTerminalDimensions(id: number, cols: number, rows: number): void; $acceptTerminalMaximumDimensions(id: number, cols: number, rows: number): void; - $createProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; + $spawnExtHostProcess(id: number, shellLaunchConfig: ShellLaunchConfigDto, activeWorkspaceRootUri: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void; $acceptProcessInput(id: number, data: string): void; $acceptProcessResize(id: number, cols: number, rows: number): void; $acceptProcessShutdown(id: number, immediate: boolean): void; @@ -1245,7 +1249,7 @@ export type IDebugSessionDto = IDebugSessionFullDto | DebugSessionUUID; export interface ExtHostDebugServiceShape { $substituteVariables(folder: UriComponents | undefined, config: IConfig): Promise; - $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; $startDASession(handle: number, session: IDebugSessionDto): Promise; $stopDASession(handle: number): Promise; $sendDAMessage(handle: number, message: DebugProtocol.ProtocolMessage): void; diff --git a/src/vs/workbench/api/common/extHostCommands.ts b/src/vs/workbench/api/common/extHostCommands.ts index dcc2f57a3d..edb1bc5ad1 100644 --- a/src/vs/workbench/api/common/extHostCommands.ts +++ b/src/vs/workbench/api/common/extHostCommands.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { validateConstraint } from 'vs/base/common/types'; -import { ICommandHandlerDescription } from 'vs/platform/commands/common/commands'; +import { ICommandHandlerDescription, ICommandEvent } from 'vs/platform/commands/common/commands'; import * as extHostTypes from 'vs/workbench/api/common/extHostTypes'; import * as extHostTypeConverter from 'vs/workbench/api/common/extHostTypeConverters'; import { cloneAndChange } from 'vs/base/common/objects'; @@ -17,6 +17,7 @@ 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 { Event, Emitter } from 'vs/base/common/event'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; interface CommandHandler { @@ -31,6 +32,9 @@ export interface ArgumentProcessor { export class ExtHostCommands implements ExtHostCommandsShape { + private readonly _onDidExecuteCommand: Emitter; + readonly onDidExecuteCommand: Event; + private readonly _commands = new Map(); private readonly _proxy: MainThreadCommandsShape; private readonly _converter: CommandsConverter; @@ -42,6 +46,11 @@ export class ExtHostCommands implements ExtHostCommandsShape { logService: ILogService ) { this._proxy = mainContext.getProxy(MainContext.MainThreadCommands); + this._onDidExecuteCommand = new Emitter({ + onFirstListenerDidAdd: () => this._proxy.$registerCommandListener(), + onLastListenerRemove: () => this._proxy.$unregisterCommandListener(), + }); + this.onDidExecuteCommand = Event.filter(this._onDidExecuteCommand.event, e => e.command[0] !== '_'); // filter 'private' commands this._logService = logService; this._converter = new CommandsConverter(this); this._argumentProcessors = [ @@ -106,6 +115,13 @@ export class ExtHostCommands implements ExtHostCommandsShape { }); } + $handleDidExecuteCommand(command: ICommandEvent): void { + this._onDidExecuteCommand.fire({ + command: command.commandId, + arguments: command.args.map(arg => this._argumentProcessors.reduce((r, p) => p.processArgument(r), arg)) + }); + } + executeCommand(id: string, ...args: any[]): Promise { this._logService.trace('ExtHostCommands#executeCommand', id); @@ -154,6 +170,7 @@ export class ExtHostCommands implements ExtHostCommandsShape { try { const result = callback.apply(thisArg, args); + this._onDidExecuteCommand.fire({ command: id, arguments: args }); return Promise.resolve(result); } catch (err) { this._logService.error(err, id); @@ -205,7 +222,7 @@ export class CommandsConverter { // --- conversion between internal and api commands constructor(commands: ExtHostCommands) { - this._delegatingCommandId = `_internal_command_delegation_${Date.now()}`; + this._delegatingCommandId = `_vscode_delegate_cmd_${Date.now().toString(36)}`; this._commands = commands; this._commands.registerCommand(true, this._delegatingCommandId, this._executeConvertedCommand, this); } diff --git a/src/vs/workbench/api/common/extHostTypeConverters.ts b/src/vs/workbench/api/common/extHostTypeConverters.ts index 8ceacbdf21..c6384916ce 100644 --- a/src/vs/workbench/api/common/extHostTypeConverters.ts +++ b/src/vs/workbench/api/common/extHostTypeConverters.ts @@ -108,6 +108,8 @@ export namespace DiagnosticTag { switch (value) { case types.DiagnosticTag.Unnecessary: return MarkerTag.Unnecessary; + case types.DiagnosticTag.Deprecated: + return MarkerTag.Deprecated; } return undefined; } @@ -988,8 +990,9 @@ export namespace GlobPattern { export function from(pattern: vscode.GlobPattern): string | types.RelativePattern; export function from(pattern: undefined): undefined; - export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined; - export function from(pattern: vscode.GlobPattern | undefined): string | types.RelativePattern | undefined { + export function from(pattern: null): null; + export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null; + export function from(pattern: vscode.GlobPattern | undefined | null): string | types.RelativePattern | undefined | null { if (pattern instanceof types.RelativePattern) { return pattern; } diff --git a/src/vs/workbench/api/common/extHostTypes.ts b/src/vs/workbench/api/common/extHostTypes.ts index ba21d0da34..464e19344a 100644 --- a/src/vs/workbench/api/common/extHostTypes.ts +++ b/src/vs/workbench/api/common/extHostTypes.ts @@ -773,6 +773,7 @@ export class SnippetString { export enum DiagnosticTag { Unnecessary = 1, + Deprecated = 2 } export enum DiagnosticSeverity { @@ -1773,19 +1774,19 @@ export class CustomExecution implements vscode.CustomExecution { } export class CustomExecution2 implements vscode.CustomExecution2 { - private _callback: () => Thenable; - constructor(callback: () => Thenable) { + private _callback: () => Thenable; + constructor(callback: () => Thenable) { this._callback = callback; } public computeId(): string { return 'customExecution' + generateUuid(); } - public set callback(value: () => Thenable) { + public set callback(value: () => Thenable) { this._callback = value; } - public get callback(): (() => Thenable) { + public get callback(): (() => Thenable) { return this._callback; } } diff --git a/src/vs/workbench/api/common/extHostWorkspace.ts b/src/vs/workbench/api/common/extHostWorkspace.ts index e6bfbd46de..717bfdd177 100644 --- a/src/vs/workbench/api/common/extHostWorkspace.ts +++ b/src/vs/workbench/api/common/extHostWorkspace.ts @@ -24,6 +24,7 @@ import { ExtHostWorkspaceShape, IWorkspaceData, MainThreadMessageServiceShape, M import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { Barrier } from 'vs/base/common/async'; import { Schemas } from 'vs/base/common/network'; +import { withUndefinedAsNull } from 'vs/base/common/types'; export interface IExtHostWorkspaceProvider { getWorkspaceFolder2(uri: vscode.Uri, resolveParent?: boolean): Promise; @@ -407,7 +408,10 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac // --- search --- - findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { + /** + * Note, null/undefined have different and important meanings for "exclude" + */ + findFiles(include: string | RelativePattern | undefined, exclude: vscode.GlobPattern | null | undefined, maxResults: number | undefined, extensionId: ExtensionIdentifier, token: vscode.CancellationToken = CancellationToken.None): Promise { this._logService.trace(`extHostWorkspace#findFiles: fileSearch, extension: ${extensionId.value}, entryPoint: findFiles`); let includePattern: string | undefined; @@ -438,7 +442,13 @@ export class ExtHostWorkspace implements ExtHostWorkspaceShape, IExtHostWorkspac return Promise.resolve([]); } - return this._proxy.$startFileSearch(includePattern, includeFolder, excludePatternOrDisregardExcludes, maxResults, token) + return this._proxy.$startFileSearch( + withUndefinedAsNull(includePattern), + withUndefinedAsNull(includeFolder), + withUndefinedAsNull(excludePatternOrDisregardExcludes), + withUndefinedAsNull(maxResults), + token + ) .then(data => Array.isArray(data) ? data.map(d => URI.revive(d)) : []); } diff --git a/src/vs/workbench/api/node/extHost.api.impl.ts b/src/vs/workbench/api/node/extHost.api.impl.ts index 19a05651e1..ccd8015af7 100644 --- a/src/vs/workbench/api/node/extHost.api.impl.ts +++ b/src/vs/workbench/api/node/extHost.api.impl.ts @@ -66,7 +66,6 @@ import * as vscode from 'vscode'; import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions'; import { originalFSPath } from 'vs/base/common/resources'; import { CLIServer } from 'vs/workbench/api/node/extHostCLIServer'; -import { withNullAsUndefined } from 'vs/base/common/types'; import { values } from 'vs/base/common/collections'; import { Schemas } from 'vs/base/common/network'; import { IURITransformer } from 'vs/base/common/uriIpc'; @@ -75,6 +74,7 @@ import { ExtHostLabelService } from 'vs/workbench/api/common/extHostLabelService import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { InstantiationService } from 'vs/platform/instantiation/common/instantiationService'; import { getSingletonServiceDescriptors } from 'vs/platform/instantiation/common/extensions'; +import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; export interface IExtensionApiFactory { (extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode; @@ -249,7 +249,11 @@ export function createApiFactory( }, getCommands(filterInternal: boolean = false): Thenable { return extHostCommands.getCommands(filterInternal); - } + }, + onDidExecuteCommand: proposedApiFunction(extension, (listener, thisArgs?, disposables?) => { + checkProposedApiEnabled(extension); + return extHostCommands.onDidExecuteCommand(listener, thisArgs, disposables); + }), }; // namespace: env @@ -278,15 +282,7 @@ export function createApiFactory( return extHostWindow.openUri(uri, { allowTunneling: !!initData.remote.isRemote }); }, get remoteName() { - if (!initData.remote.authority) { - return undefined; - } - const pos = initData.remote.authority.indexOf('+'); - if (pos < 0) { - // funky? bad authority? - return initData.remote.authority; - } - return initData.remote.authority.substr(0, pos); + return getRemoteName(initData.remote.authority); } }; if (!initData.environment.extensionTestsLocationURI) { @@ -540,10 +536,10 @@ export function createApiFactory( checkProposedApiEnabled(extension); return extHostEditorInsets.createWebviewEditorInset(editor, line, height, options, extension); }, - createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.TerminalVirtualProcessOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { + createTerminal(nameOrOptions?: vscode.TerminalOptions | vscode.ExtensionTerminalOptions | string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { if (typeof nameOrOptions === 'object') { - if ('virtualProcess' in nameOrOptions) { - return extHostTerminalService.createVirtualProcessTerminal(nameOrOptions); + if ('pty' in nameOrOptions) { + return extHostTerminalService.createExtensionTerminal(nameOrOptions); } else { nameOrOptions.hideFromUser = nameOrOptions.hideFromUser || (nameOrOptions.runInBackground && extension.enableProposedApi); return extHostTerminalService.createTerminalFromOptions(nameOrOptions); @@ -613,7 +609,8 @@ export function createApiFactory( return extHostWorkspace.getRelativePath(pathOrUri, includeWorkspace); }, findFiles: (include, exclude, maxResults?, token?) => { - return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(withNullAsUndefined(exclude)), maxResults, extension.identifier, token); + // Note, undefined/null have different meanings on "exclude" + return extHostWorkspace.findFiles(typeConverters.GlobPattern.from(include), typeConverters.GlobPattern.from(exclude), maxResults, extension.identifier, token); }, findTextInFiles: (query: vscode.TextSearchQuery, optionsOrCallback: vscode.FindTextInFilesOptions | ((result: vscode.TextSearchResult) => void), callbackOrToken?: vscode.CancellationToken | ((result: vscode.TextSearchResult) => void), token?: vscode.CancellationToken) => { let options: vscode.FindTextInFilesOptions; diff --git a/src/vs/workbench/api/node/extHostDebugService.ts b/src/vs/workbench/api/node/extHostDebugService.ts index 90e32e1f41..ce0805dc58 100644 --- a/src/vs/workbench/api/node/extHostDebugService.ts +++ b/src/vs/workbench/api/node/extHostDebugService.ts @@ -20,7 +20,7 @@ import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstract import { IExtHostWorkspaceProvider } from 'vs/workbench/api/common/extHostWorkspace'; import { ExtHostExtensionService } from 'vs/workbench/api/node/extHostExtensionService'; import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors'; -import { ITerminalSettings, IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor } from 'vs/workbench/contrib/debug/common/debug'; import { hasChildProcesses, prepareCommand, runInExternalTerminal } from 'vs/workbench/contrib/debug/node/terminals'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver'; @@ -34,6 +34,8 @@ import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands'; import { ExtensionDescriptionRegistry } from 'vs/workbench/services/extensions/common/extensionDescriptionRegistry'; import { IProcessEnvironment } from 'vs/base/common/platform'; import { IExtensionDescription } from 'vs/platform/extensions/common/extensions'; +import { SignService } from 'vs/platform/sign/node/signService'; +import { ISignService } from 'vs/platform/sign/common/sign'; export class ExtHostDebugService implements ExtHostDebugServiceShape { @@ -81,6 +83,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { private _integratedTerminalInstance?: vscode.Terminal; private _terminalDisposedListener: IDisposable; + private _signService: ISignService; + constructor(mainContext: IMainContext, private _workspaceService: IExtHostWorkspaceProvider, @@ -314,7 +318,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { // RPC methods (ExtHostDebugServiceShape) - public $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + public async $runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { if (args.kind === 'integrated') { @@ -337,10 +341,22 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else { resolve(true); } - }).then(needNewTerminal => { + }).then(async needNewTerminal => { + + const configProvider = await this._configurationService.getConfigProvider(); + const shell = this._terminalService.getDefaultShell(configProvider); if (needNewTerminal || !this._integratedTerminalInstance) { - this._integratedTerminalInstance = this._terminalService.createTerminal(args.title || nls.localize('debug.terminal.title', "debuggee")); + const options: vscode.TerminalOptions = { + shellPath: shell, + // shellArgs: this._terminalService._getDefaultShellArgs(configProvider), + cwd: args.cwd, + name: args.title || nls.localize('debug.terminal.title', "debuggee"), + env: args.env + }; + delete args.cwd; + delete args.env; + this._integratedTerminalInstance = this._terminalService.createTerminalFromOptions(options); } const terminal: vscode.Terminal = this._integratedTerminalInstance; @@ -348,7 +364,8 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { return this._integratedTerminalInstance.processId.then(shellProcessId => { - const command = prepareCommand(args, config); + const command = prepareCommand(args, shell, configProvider); + terminal.sendText(command, true); return shellProcessId; @@ -357,7 +374,7 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { } else if (args.kind === 'external') { - runInExternalTerminal(args, config); + runInExternalTerminal(args, await this._configurationService.getConfigProvider()); } return Promise.resolve(undefined); } @@ -421,16 +438,45 @@ export class ExtHostDebugService implements ExtHostDebugServiceShape { this._debugAdaptersTrackers.set(debugAdapterHandle, tracker); } - debugAdapter.onMessage(message => { + debugAdapter.onMessage(async message => { - if (tracker && tracker.onDidSendMessage) { - tracker.onDidSendMessage(message); + if (message.type === 'request' && (message).command === 'handshake') { + + const request = message; + + const response: DebugProtocol.Response = { + type: 'response', + seq: 0, + command: request.command, + request_seq: request.seq, + success: true + }; + + if (!this._signService) { + this._signService = new SignService(); + } + + try { + const signature = await this._signService.sign(request.arguments.value); + response.body = { + signature: signature + }; + debugAdapter.sendResponse(response); + } catch (e) { + response.success = false; + response.message = e.message; + debugAdapter.sendResponse(response); + } + } else { + if (tracker && tracker.onDidSendMessage) { + tracker.onDidSendMessage(message); + } + + // DA -> VS Code + message = convertToVSCPaths(message, true); + + mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message); } - - // DA -> VS Code - message = convertToVSCPaths(message, true); - - mythis._debugServiceProxy.$acceptDAMessage(debugAdapterHandle, message); }); debugAdapter.onError(err => { if (tracker && tracker.onError) { diff --git a/src/vs/workbench/api/node/extHostExtensionService.ts b/src/vs/workbench/api/node/extHostExtensionService.ts index 5b2fe81ba1..fdbc343074 100644 --- a/src/vs/workbench/api/node/extHostExtensionService.ts +++ b/src/vs/workbench/api/node/extHostExtensionService.ts @@ -322,15 +322,6 @@ export class ExtHostExtensionService implements ExtHostExtensionServiceShape { private _logExtensionActivationTimes(extensionDescription: IExtensionDescription, reason: ExtensionActivationReason, outcome: string, activationTimes?: ExtensionActivationTimes) { const event = getTelemetryActivationEvent(extensionDescription, reason); - /* __GDPR__ - "extensionActivationTimes" : { - "${include}": [ - "${TelemetryActivationEvent}", - "${ExtensionActivationTimes}" - ], - "outcome" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ type ExtensionActivationTimesClassification = { outcome: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; } & TelemetryActivationEventFragment & ExtensionActivationTimesFragment; diff --git a/src/vs/workbench/api/node/extHostTask.ts b/src/vs/workbench/api/node/extHostTask.ts index e41f80f654..9e011a7eb6 100644 --- a/src/vs/workbench/api/node/extHostTask.ts +++ b/src/vs/workbench/api/node/extHostTask.ts @@ -589,9 +589,7 @@ export class ExtHostTask implements ExtHostTaskShape { // Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task. this._activeCustomExecutions2.set(execution.id, execution2); - this._terminalService.performTerminalIdAction(terminalId, async terminal => { - this._terminalService.attachVirtualProcessToTerminal(terminalId, await execution2.callback()); - }); + await this._terminalService.attachPtyToTerminal(terminalId, await execution2.callback()); } // Once a terminal is spun up for the custom execution task this event will be fired. diff --git a/src/vs/workbench/api/node/extHostTerminalService.ts b/src/vs/workbench/api/node/extHostTerminalService.ts index f955a345e5..8dd7a13301 100644 --- a/src/vs/workbench/api/node/extHostTerminalService.ts +++ b/src/vs/workbench/api/node/extHostTerminalService.ts @@ -91,7 +91,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi this._idPromise.then(c => { this._proxy.$registerOnDataListener(this._id); }); - return this._onData && this._onData.event; + return this._onData.event; } constructor( @@ -110,7 +110,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi }); } - public create( + public async create( shellPath?: string, shellArgs?: string[] | string, cwd?: string | URI, @@ -118,18 +118,16 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi waitOnExit?: boolean, strictEnv?: boolean, hideFromUser?: boolean - ): void { - this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser }).then(terminal => { - this._name = terminal.name; - this._runQueuedRequests(terminal.id); - }); + ): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, shellPath, shellArgs, cwd, env, waitOnExit, strictEnv, hideFromUser }); + this._name = terminal.name; + this._runQueuedRequests(terminal.id); } - public createVirtualProcess(): Promise { - return this._proxy.$createTerminal({ name: this._name, isVirtualProcess: true }).then(terminal => { - this._name = terminal.name; - this._runQueuedRequests(terminal.id); - }); + public async createExtensionTerminal(): Promise { + const terminal = await this._proxy.$createTerminal({ name: this._name, isExtensionTerminal: true }); + this._name = terminal.name; + this._runQueuedRequests(terminal.id); } public get name(): string { @@ -312,9 +310,9 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { private _logService: ILogService ) { this._proxy = mainContext.getProxy(MainContext.MainThreadTerminalService); - this.updateLastActiveWorkspace(); - this.updateVariableResolver(); - this.registerListeners(); + this._updateLastActiveWorkspace(); + this._updateVariableResolver(); + this._registerListeners(); } public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal { @@ -331,20 +329,20 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return terminal; } - public createVirtualProcessTerminal(options: vscode.TerminalVirtualProcessOptions): vscode.Terminal { + public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal { const terminal = new ExtHostTerminal(this._proxy, options.name); - const p = new ExtHostVirtualProcess(options.virtualProcess); - terminal.createVirtualProcess().then(() => this._setupExtHostProcessListeners(terminal._id, p)); + const p = new ExtHostPseudoterminal(options.pty); + terminal.createExtensionTerminal().then(() => this._setupExtHostProcessListeners(terminal._id, p)); this._terminals.push(terminal); return terminal; } - public attachVirtualProcessToTerminal(id: number, virtualProcess: vscode.TerminalVirtualProcess) { - const terminal = this._getTerminalById(id); + public async attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): Promise { + const terminal = this._getTerminalByIdEventually(id); if (!terminal) { throw new Error(`Cannot resolve terminal with id ${id} for virtual process`); } - const p = new ExtHostVirtualProcess(virtualProcess); + const p = new ExtHostPseudoterminal(pty); this._setupExtHostProcessListeners(id, p); } @@ -534,25 +532,25 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { return env; } - private registerListeners(): void { - this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this.updateLastActiveWorkspace()); - this._extHostWorkspace.onDidChangeWorkspace(() => this.updateVariableResolver()); + private _registerListeners(): void { + this._extHostDocumentsAndEditors.onDidChangeActiveTextEditor(() => this._updateLastActiveWorkspace()); + this._extHostWorkspace.onDidChangeWorkspace(() => this._updateVariableResolver()); } - private updateLastActiveWorkspace(): void { + private _updateLastActiveWorkspace(): void { const activeEditor = this._extHostDocumentsAndEditors.activeEditor(); if (activeEditor) { this._lastActiveWorkspace = this._extHostWorkspace.getWorkspaceFolder(activeEditor.document.uri) as IWorkspaceFolder; } } - private async updateVariableResolver(): Promise { + private async _updateVariableResolver(): Promise { const configProvider = await this._extHostConfiguration.getConfigProvider(); const workspaceFolders = await this._extHostWorkspace.getWorkspaceFolders2(); this._variableResolver = new ExtHostVariableResolverService(workspaceFolders || [], this._extHostDocumentsAndEditors, configProvider); } - public async $createProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { + public async $spawnExtHostProcess(id: number, shellLaunchConfigDto: ShellLaunchConfigDto, activeWorkspaceRootUriComponents: UriComponents, cols: number, rows: number, isWorkspaceShellAllowed: boolean): Promise { const shellLaunchConfig: IShellLaunchConfig = { name: shellLaunchConfigDto.name, executable: shellLaunchConfigDto.executable, @@ -612,6 +610,7 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { baseEnv ); + this._proxy.$sendResolvedLaunchConfig(id, shellLaunchConfig); // Fork the process and listen for messages this._logService.debug(`Terminal process launching on ext host`, shellLaunchConfig, initialCwd, cols, rows, env); // TODO: Support conpty on remote, it doesn't seem to work for some reason? @@ -620,8 +619,22 @@ export class ExtHostTerminalService implements ExtHostTerminalServiceShape { this._setupExtHostProcessListeners(id, new TerminalProcess(shellLaunchConfig, initialCwd, cols, rows, env, enableConpty, this._logService)); } - public $startVirtualProcess(id: number, initialDimensions: ITerminalDimensionsDto | undefined): void { - (this._terminalProcesses[id] as ExtHostVirtualProcess).startSendingEvents(initialDimensions); + public async $startExtensionTerminal(id: number, initialDimensions: ITerminalDimensionsDto | undefined): Promise { + // Make sure the ExtHostTerminal exists so onDidOpenTerminal has fired before we call + // Pseudoterminal.start + await this._getTerminalByIdEventually(id); + + // Processes should be initialized here for normal virtual process terminals, however for + // tasks they are responsible for attaching the virtual process to a terminal so this + // function may be called before tasks is able to attach to the terminal. + let retries = 5; + while (retries-- > 0) { + if (this._terminalProcesses[id]) { + (this._terminalProcesses[id] as ExtHostPseudoterminal).startSendingEvents(initialDimensions); + return; + } + await timeout(50); + } } private _setupExtHostProcessListeners(id: number, p: ITerminalChildProcess): void { @@ -760,7 +773,7 @@ class ApiRequest { } } -class ExtHostVirtualProcess implements ITerminalChildProcess { +class ExtHostPseudoterminal implements ITerminalChildProcess { private _queuedEvents: (IQueuedEvent | IQueuedEvent | IQueuedEvent<{ pid: number, cwd: string }> | IQueuedEvent)[] = []; private _queueDisposables: IDisposable[] | undefined; @@ -776,33 +789,33 @@ class ExtHostVirtualProcess implements ITerminalChildProcess { public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } constructor( - private readonly _virtualProcess: vscode.TerminalVirtualProcess + private readonly _pty: vscode.Pseudoterminal ) { this._queueDisposables = []; - this._queueDisposables.push(this._virtualProcess.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); - if (this._virtualProcess.onDidExit) { - this._queueDisposables.push(this._virtualProcess.onDidExit(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: e }))); + this._queueDisposables.push(this._pty.onDidWrite(e => this._queuedEvents.push({ emitter: this._onProcessData, data: e }))); + if (this._pty.onDidClose) { + this._queueDisposables.push(this._pty.onDidClose(e => this._queuedEvents.push({ emitter: this._onProcessExit, data: 0 }))); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._queueDisposables.push(this._virtualProcess.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); + if (this._pty.onDidOverrideDimensions) { + this._queueDisposables.push(this._pty.onDidOverrideDimensions(e => this._queuedEvents.push({ emitter: this._onProcessOverrideDimensions, data: e ? { cols: e.columns, rows: e.rows } : undefined }))); } } shutdown(): void { - if (this._virtualProcess.shutdown) { - this._virtualProcess.shutdown(); + if (this._pty.close) { + this._pty.close(); } } input(data: string): void { - if (this._virtualProcess.handleInput) { - this._virtualProcess.handleInput(data); + if (this._pty.handleInput) { + this._pty.handleInput(data); } } resize(cols: number, rows: number): void { - if (this._virtualProcess.setDimensions) { - this._virtualProcess.setDimensions({ columns: cols, rows }); + if (this._pty.setDimensions) { + this._pty.setDimensions({ columns: cols, rows }); } } @@ -825,19 +838,16 @@ class ExtHostVirtualProcess implements ITerminalChildProcess { this._queueDisposables = undefined; // Attach the real listeners - this._virtualProcess.onDidWrite(e => this._onProcessData.fire(e)); - if (this._virtualProcess.onDidExit) { - this._virtualProcess.onDidExit(e => { - // Ensure only positive exit codes are returned - this._onProcessExit.fire(e >= 0 ? e : 1); - }); + this._pty.onDidWrite(e => this._onProcessData.fire(e)); + if (this._pty.onDidClose) { + this._pty.onDidClose(e => this._onProcessExit.fire(0)); } - if (this._virtualProcess.onDidOverrideDimensions) { - this._virtualProcess.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-check + if (this._pty.onDidOverrideDimensions) { + this._pty.onDidOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e ? { cols: e.columns, rows: e.rows } : undefined)); // {{SQL CARBON EDIT}} strict-null-checks } - if (this._virtualProcess.start) { - this._virtualProcess.start(initialDimensions); + if (this._pty.open) { + this._pty.open(initialDimensions); } } } diff --git a/src/vs/workbench/browser/contextkeys.ts b/src/vs/workbench/browser/contextkeys.ts index e9311871c0..55edb94332 100644 --- a/src/vs/workbench/browser/contextkeys.ts +++ b/src/vs/workbench/browser/contextkeys.ts @@ -20,6 +20,7 @@ import { IWorkbenchLayoutService, Parts, Position } from 'vs/workbench/services/ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { isMacintosh, isLinux, isWindows, isWeb } from 'vs/base/common/platform'; import { PanelPositionContext } from 'vs/workbench/common/panel'; +import { getRemoteName } from 'vs/platform/remote/common/remoteHosts'; export const IsMacContext = new RawContextKey('isMac', isMacintosh); export const IsLinuxContext = new RawContextKey('isLinux', isLinux); @@ -28,8 +29,9 @@ export const IsWindowsContext = new RawContextKey('isWindows', isWindow export const IsWebContext = new RawContextKey('isWeb', isWeb); export const IsMacNativeContext = new RawContextKey('isMacNative', isMacintosh && !isWeb); -export const RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); +export const Deprecated_RemoteAuthorityContext = new RawContextKey('remoteAuthority', ''); +export const RemoteNameContext = new RawContextKey('remoteName', ''); export const RemoteConnectionState = new RawContextKey<'' | 'initializing' | 'disconnected' | 'connected'>('remoteConnectionState', ''); export const HasMacNativeTabsContext = new RawContextKey('hasMacNativeTabs', false); @@ -121,7 +123,7 @@ export class WorkbenchContextKeysHandler extends Disposable { IsWebContext.bindTo(this.contextKeyService); IsMacNativeContext.bindTo(this.contextKeyService); - RemoteAuthorityContext.bindTo(this.contextKeyService).set(this.environmentService.configuration.remoteAuthority || ''); + RemoteNameContext.bindTo(this.contextKeyService).set(getRemoteName(this.environmentService.configuration.remoteAuthority) || ''); // macOS Native Tabs const windowConfig = this.configurationService.getValue(); diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index b2c3218965..5a7b81d4e0 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -5,7 +5,7 @@ import { Disposable, DisposableStore } 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, EventHelper, Dimension } 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'; @@ -545,6 +545,10 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi return true; // any other part cannot be hidden } + getDimension(part: Parts): Dimension { + return this.getPart(part).dimension; + } + getTitleBarOffset(): number { let offset = 0; if (this.isVisible(Parts.TITLEBAR_PART)) { diff --git a/src/vs/workbench/browser/legacyLayout.ts b/src/vs/workbench/browser/legacyLayout.ts index 7ab65c62ba..3239b25572 100644 --- a/src/vs/workbench/browser/legacyLayout.ts +++ b/src/vs/workbench/browser/legacyLayout.ts @@ -626,11 +626,11 @@ export class WorkbenchLegacyLayout extends Disposable implements IVerticalSashLa } // Propagate to Part Layouts - this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight, -1); - this.parts.editor.layout(editorSize.width, editorSize.height, -1); - this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height, -1); - this.parts.panel.layout(panelDimension.width, panelDimension.height, -1); - this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height, -1); + this.parts.titlebar.layout(this.workbenchSize.width, this.titlebarHeight); + this.parts.editor.layout(editorSize.width, editorSize.height); + this.parts.sidebar.layout(sidebarSize.width, sidebarSize.height); + this.parts.panel.layout(panelDimension.width, panelDimension.height); + this.parts.activitybar.layout(activityBarSize.width, activityBarSize.height); // Propagate to Context View this.contextViewService.layout(); diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index 2cf2768b79..6aadf410cc 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -9,10 +9,9 @@ import { IThemeService, ITheme } from 'vs/platform/theme/common/themeService'; import { Dimension, size } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { IDimension } from 'vs/platform/layout/browser/layoutService'; -import { ISerializableView, Orientation } from 'vs/base/browser/ui/grid/grid'; +import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; -import { IViewSize } from 'vs/base/browser/ui/grid/gridview'; export interface IPartOptions { hasTitle?: boolean; @@ -29,6 +28,10 @@ export interface ILayoutContentResult { * arranges an optional title and mandatory content area to show content. */ export abstract class Part extends Component implements ISerializableView { + + private _dimension: Dimension; + get dimension(): Dimension { return this._dimension; } + private parent: HTMLElement; private titleArea: HTMLElement | null; private contentArea: HTMLElement | null; @@ -128,7 +131,10 @@ export abstract class Part extends Component implements ISerializableView { abstract minimumHeight: number; abstract maximumHeight: number; - abstract layout(width: number, height: number, orientation: Orientation): void; + layout(width: number, height: number): void { + this._dimension = new Dimension(width, height); + } + abstract toJSON(): object; //#endregion @@ -164,4 +170,4 @@ class PartLayout { return { titleSize, contentSize }; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts index 09bafdbd1b..1dc23193df 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarActions.ts @@ -72,13 +72,11 @@ export class ViewletActivityAction extends ActivityAction { } private logAction(action: string) { - /* __GDPR__ - "activityBarAction" : { - "viewletId": { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "action": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('activityBarAction', { viewletId: this.activity.id, action }); + type ActivityBarActionClassification = { + viewletId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + action: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ viewletId: String, action: String }, ActivityBarActionClassification>('activityBarAction', { viewletId: this.activity.id, action }); } } @@ -165,7 +163,7 @@ export class GlobalActivityActionViewItem extends ActivityActionViewItem { export class PlaceHolderViewletActivityAction extends ViewletActivityAction { constructor( - id: string, iconUrl: URI, + id: string, name: string, iconUrl: URI, @IViewletService viewletService: IViewletService, @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @ITelemetryService telemetryService: ITelemetryService diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index e73baaf8b7..bf0d9a2242 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -34,9 +34,11 @@ import { isUndefinedOrNull } from 'vs/base/common/types'; import { IActivityBarService } from 'vs/workbench/services/activityBar/browser/activityBarService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Schemas } from 'vs/base/common/network'; +import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; interface ICachedViewlet { id: string; + name?: string; iconUrl?: UriComponents; pinned: boolean; order?: number; @@ -78,18 +80,23 @@ export class ActivitybarPart extends Part implements IActivityBarService { @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, @IViewsService private readonly viewsService: IViewsService, - @IContextKeyService private readonly contextKeyService: IContextKeyService + @IContextKeyService private readonly contextKeyService: IContextKeyService, + @IWorkbenchEnvironmentService workbenchEnvironmentService: IWorkbenchEnvironmentService, ) { super(Parts.ACTIVITYBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); this.cachedViewlets = this.getCachedViewlets(); for (const cachedViewlet of this.cachedViewlets) { - if (this.shouldBeHidden(cachedViewlet.id, cachedViewlet)) { + if (workbenchEnvironmentService.configuration.remoteAuthority // In remote window, hide activity bar entries until registered. + || this.shouldBeHidden(cachedViewlet.id, cachedViewlet) + ) { cachedViewlet.visible = false; } } - this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, this.cachedViewlets.map(v => ({ id: v.id, name: undefined, visible: v.visible, order: v.order, pinned: v.pinned })), { + const cachedItems = this.cachedViewlets + .map(v => ({ id: v.id, name: v.name, visible: v.visible, order: v.order, pinned: v.pinned })); + this.compositeBar = this._register(this.instantiationService.createInstance(CompositeBar, cachedItems, { icon: true, orientation: ActionsOrientation.VERTICAL, openComposite: (compositeId: string) => this.viewletService.openViewlet(compositeId, true), @@ -252,7 +259,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } else { const cachedComposite = this.cachedViewlets.filter(c => c.id === compositeId)[0]; compositeActions = { - activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), + activityAction: this.instantiationService.createInstance(PlaceHolderViewletActivityAction, compositeId, cachedComposite && cachedComposite.name ? cachedComposite.name : compositeId, cachedComposite && cachedComposite.iconUrl ? URI.revive(cachedComposite.iconUrl) : undefined), pinnedAction: new PlaceHolderToggleCompositePinnedAction(compositeId, this.compositeBar) }; } @@ -312,7 +319,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } - private shouldBeHidden(viewletId: string, cachedViewlet: ICachedViewlet): boolean { + private shouldBeHidden(viewletId: string, cachedViewlet?: ICachedViewlet): boolean { const viewContainer = this.getViewContainer(viewletId); if (!viewContainer || !viewContainer.hideIfEmpty) { return false; @@ -428,7 +435,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { } } } - state.push({ id: compositeItem.id, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); + state.push({ id: compositeItem.id, name: viewlet.name, iconUrl: viewlet.iconUrl && viewlet.iconUrl.scheme === Schemas.file ? viewlet.iconUrl : undefined, views, pinned: compositeItem.pinned, order: compositeItem.order, visible: compositeItem.visible }); } else { state.push({ id: compositeItem.id, pinned: compositeItem.pinned, order: compositeItem.order, visible: false }); } @@ -440,7 +447,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { private getCachedViewlets(): ICachedViewlet[] { const storedStates: Array = JSON.parse(this.cachedViewletsValue); const cachedViewlets = storedStates.map(c => { - const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, iconUrl: undefined, views: undefined } : c; + const serialized: ICachedViewlet = typeof c === 'string' /* migration from pinned states to composites states */ ? { id: c, pinned: true, order: undefined, visible: true, name: undefined, iconUrl: undefined, views: undefined } : c; serialized.visible = isUndefinedOrNull(serialized.visible) ? true : serialized.visible; return serialized; }); @@ -448,6 +455,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { for (const old of this.loadOldCachedViewlets()) { const cachedViewlet = cachedViewlets.filter(cached => cached.id === old.id)[0]; if (cachedViewlet) { + cachedViewlet.name = old.name; cachedViewlet.iconUrl = old.iconUrl; cachedViewlet.views = old.views; } diff --git a/src/vs/workbench/browser/parts/compositePart.ts b/src/vs/workbench/browser/parts/compositePart.ts index 384ebdd6ba..0031831894 100644 --- a/src/vs/workbench/browser/parts/compositePart.ts +++ b/src/vs/workbench/browser/parts/compositePart.ts @@ -466,6 +466,7 @@ export abstract class CompositePart extends Part { } layout(width: number, height: number): void { + super.layout(width, height); // Layout contents this.contentAreaSize = super.layoutContents(width, height).contentSize; diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts index 9e7c3a7400..b7f03dcbb0 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsControl.ts @@ -304,12 +304,10 @@ export class BreadcrumbsControl { const { element } = event.item as Item; this._editorGroup.focus(); - /* __GDPR__ - "breadcrumbs/select" : { - "type": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this._telemetryService.publicLog('breadcrumbs/select', { type: element instanceof TreeElement ? 'symbol' : 'file' }); + type BreadcrumbSelectClassification = { + type: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this._telemetryService.publicLog2<{ type: string }, BreadcrumbSelectClassification>('breadcrumbs/select', { type: element instanceof TreeElement ? 'symbol' : 'file' }); const group = this._getEditorGroup(event.payload); if (group !== undefined) { diff --git a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts index 7131e50a75..12c25f368f 100644 --- a/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts +++ b/src/vs/workbench/browser/parts/editor/breadcrumbsPicker.ts @@ -25,10 +25,9 @@ import { ResourceLabels, IResourceLabel, DEFAULT_LABELS_CONTAINER } from 'vs/wor import { BreadcrumbsConfig } from 'vs/workbench/browser/parts/editor/breadcrumbs'; import { BreadcrumbElement, FileElement } from 'vs/workbench/browser/parts/editor/breadcrumbsModel'; import { IFileIconTheme, IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService'; -import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, ITreeSorter, IDataSource } from 'vs/base/browser/ui/tree/tree'; -import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder, OutlineItem } from 'vs/editor/contrib/documentSymbols/outlineTree'; +import { IAsyncDataSource, ITreeRenderer, ITreeNode, ITreeFilter, TreeVisibility, ITreeSorter } from 'vs/base/browser/ui/tree/tree'; +import { OutlineVirtualDelegate, OutlineGroupRenderer, OutlineElementRenderer, OutlineItemComparator, OutlineIdentityProvider, OutlineNavigationLabelProvider, OutlineDataSource, OutlineSortOrder } from 'vs/editor/contrib/documentSymbols/outlineTree'; import { IIdentityProvider, IListVirtualDelegate, IKeyboardNavigationLabelProvider } from 'vs/base/browser/ui/list/list'; -import { IDataTreeOptions } from 'vs/base/browser/ui/tree/dataTree'; export function createBreadcrumbsPicker(instantiationService: IInstantiationService, parent: HTMLElement, element: BreadcrumbElement): BreadcrumbsPicker { const ctor: IConstructorSignature1 = element instanceof FileElement @@ -381,7 +380,7 @@ export class BreadcrumbsFilePicker extends BreadcrumbsPicker { filter: this._instantiationService.createInstance(FileFilter), identityProvider: new FileIdentityProvider(), keyboardNavigationLabelProvider: new FileNavigationLabelProvider() - }) as WorkbenchAsyncDataTree; + }); } _setInput(element: BreadcrumbElement): Promise { @@ -439,14 +438,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { } protected _createTree(container: HTMLElement) { - return this._instantiationService.createInstance< - HTMLElement, - IListVirtualDelegate, - ITreeRenderer[], - IDataSource, - IDataTreeOptions, - WorkbenchDataTree - >( + return this._instantiationService.createInstance( WorkbenchDataTree, container, new OutlineVirtualDelegate(), @@ -459,7 +451,7 @@ export class BreadcrumbsOutlinePicker extends BreadcrumbsPicker { identityProvider: new OutlineIdentityProvider(), keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() } - ) as WorkbenchDataTree; + ); } dispose(): void { diff --git a/src/vs/workbench/browser/parts/editor/editor.contribution.ts b/src/vs/workbench/browser/parts/editor/editor.contribution.ts index 41d4d74703..770a4a5a6a 100644 --- a/src/vs/workbench/browser/parts/editor/editor.contribution.ts +++ b/src/vs/workbench/browser/parts/editor/editor.contribution.ts @@ -453,7 +453,7 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: editorCommands. interface IEditorToolItem { id: string; title: string; iconDark: string; iconLight: string; } -function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr, order: number, alternative?: IEditorToolItem): void { +function appendEditorToolItem(primary: IEditorToolItem, when: ContextKeyExpr | undefined, order: number, alternative?: IEditorToolItem): void { const item: IMenuItem = { command: { id: primary.id, diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 6b8e14af38..bb5bf7bae7 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -11,7 +11,7 @@ import { Event, Emitter, Relay } from 'vs/base/common/event'; import { contrastBorder, editorBackground } from 'vs/platform/theme/common/colorRegistry'; import { GroupDirection, IAddGroupOptions, GroupsArrangement, GroupOrientation, IMergeGroupOptions, MergeGroupMode, ICopyEditorOptions, GroupsOrder, GroupChangeKind, GroupLocation, IFindGroupScope, EditorGroupLayout, GroupLayoutArgument, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IInstantiationService, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; -import { Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; +import { IView, orthogonal, LayoutPriority, IViewSize, Direction, SerializableGrid, Sizing, ISerializedGrid, Orientation, GridBranchNode, isGridBranchNode, GridNode, createSerializedGrid, Grid } from 'vs/base/browser/ui/grid/grid'; import { GroupIdentifier, IWorkbenchEditorConfiguration, IEditorPartOptions } from 'vs/workbench/common/editor'; import { values } from 'vs/base/common/map'; import { EDITOR_GROUP_BORDER, EDITOR_PANE_BACKGROUND } from 'vs/workbench/common/theme'; @@ -27,7 +27,6 @@ import { EditorDropTarget } from 'vs/workbench/browser/parts/editor/editorDropTa import { localize } from 'vs/nls'; import { Color } from 'vs/base/common/color'; import { CenteredViewLayout } from 'vs/base/browser/ui/centered/centeredViewLayout'; -import { IView, orthogonal, LayoutPriority, IViewSize } from 'vs/base/browser/ui/grid/gridview'; 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'; @@ -112,13 +111,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro private _onDidSizeConstraintsChange = this._register(new Relay<{ width: number; height: number; } | undefined>()); get onDidSizeConstraintsChange(): Event<{ width: number; height: number; } | undefined> { return Event.any(this.onDidSetGridWidget.event, this._onDidSizeConstraintsChange.event); } - private readonly _onDidPreferredSizeChange: Emitter = this._register(new Emitter()); - readonly onDidPreferredSizeChange: Event = this._onDidPreferredSizeChange.event; - //#endregion - private _preferredSize: Dimension | undefined; - private readonly workspaceMemento: MementoObject; private readonly globalMemento: MementoObject; @@ -205,8 +199,8 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro //#region IEditorGroupsService - private _dimension: Dimension; - get dimension(): Dimension { return this._dimension; } + private _contentDimension: Dimension; + get contentDimension(): Dimension { return this._contentDimension; } get activeGroup(): IEditorGroupView { return this._activeGroup; @@ -366,9 +360,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro const newOrientation = (orientation === GroupOrientation.HORIZONTAL) ? Orientation.HORIZONTAL : Orientation.VERTICAL; if (this.gridWidget.orientation !== newOrientation) { this.gridWidget.orientation = newOrientation; - - // Mark preferred size as changed - this.resetPreferredSize(); } } @@ -418,14 +409,11 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro this.doCreateGridControlWithState(gridDescriptor, activeGroup.id, currentGroupViews); // Layout - this.doLayout(this._dimension); + this.doLayout(this._contentDimension); // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Events for groups that got added this.getGroups(GroupsOrder.GRID_APPEARANCE).forEach(groupView => { if (currentGroupViews.indexOf(groupView) === -1) { @@ -490,9 +478,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidAddGroup.fire(newGroupView); @@ -661,9 +646,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro // Update container this.updateContainer(); - // Mark preferred size as changed - this.resetPreferredSize(); - // Event this._onDidRemoveGroup.fire(groupView); } @@ -764,23 +746,6 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro get onDidChange(): Event { return this.centeredLayoutWidget.onDidChange; } readonly priority: LayoutPriority = LayoutPriority.High; - get preferredSize(): Dimension { - if (!this._preferredSize) { - this._preferredSize = new Dimension(this.gridWidget.minimumWidth, this.gridWidget.minimumHeight); - } - - return this._preferredSize; - } - - private resetPreferredSize(): void { - - // Reset (will be computed upon next access) - this._preferredSize = undefined; - - // Event - this._onDidPreferredSizeChange.fire(); - } - private get gridSeparatorBorder(): Color { return this.theme.getColor(EDITOR_GROUP_BORDER) || this.theme.getColor(contrastBorder) || Color.transparent; } @@ -968,10 +933,10 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } private doLayout(dimension: Dimension): void { - this._dimension = dimension; + this._contentDimension = dimension; // Layout Grid - this.centeredLayoutWidget.layout(this._dimension.width, this._dimension.height); + this.centeredLayoutWidget.layout(this._contentDimension.width, this._contentDimension.height); // Event this._onDidLayout.fire(dimension); @@ -1028,4 +993,4 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro } } -registerSingleton(IEditorGroupsService, EditorPart); \ No newline at end of file +registerSingleton(IEditorGroupsService, EditorPart); diff --git a/src/vs/workbench/browser/parts/notifications/notificationsList.ts b/src/vs/workbench/browser/parts/notifications/notificationsList.ts index c91720b6a7..6142b9ca2f 100644 --- a/src/vs/workbench/browser/parts/notifications/notificationsList.ts +++ b/src/vs/workbench/browser/parts/notifications/notificationsList.ts @@ -70,7 +70,7 @@ export class NotificationsList extends Themable { const renderer = this.instantiationService.createInstance(NotificationRenderer, actionRunner); // List - this.list = this._register(>this.instantiationService.createInstance( + this.list = this._register(this.instantiationService.createInstance( WorkbenchList, this.listContainer, new NotificationsListDelegate(this.listContainer), diff --git a/src/vs/workbench/browser/parts/panel/panelPart.ts b/src/vs/workbench/browser/parts/panel/panelPart.ts index c4960ab7ad..183193bee5 100644 --- a/src/vs/workbench/browser/parts/panel/panelPart.ts +++ b/src/vs/workbench/browser/parts/panel/panelPart.ts @@ -59,6 +59,16 @@ export class PanelPart extends CompositePart implements IPanelService { readonly snap = true; + get preferredHeight(): number | undefined { + const sidebarDimension = this.layoutService.getDimension(Parts.SIDEBAR_PART); + return sidebarDimension.height * 0.4; + } + + get preferredWidth(): number | undefined { + const statusbarPart = this.layoutService.getDimension(Parts.STATUSBAR_PART); + return statusbarPart.width * 0.4; + } + //#endregion get onDidPanelOpen(): Event<{ panel: IPanel, focus: boolean }> { return Event.map(this.onDidCompositeOpen.event, compositeOpen => ({ panel: compositeOpen.composite, focus: compositeOpen.focus })); } @@ -74,7 +84,7 @@ export class PanelPart extends CompositePart implements IPanelService { private compositeActions: Map = new Map(); private blockOpeningPanel: boolean; - private dimension: Dimension; + private _contentDimension: Dimension; constructor( @INotificationService notificationService: INotificationService, @@ -293,21 +303,21 @@ export class PanelPart extends CompositePart implements IPanelService { } if (this.layoutService.getPanelPosition() === Position.RIGHT) { - this.dimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting + this._contentDimension = new Dimension(width - 1, height!); // Take into account the 1px border when layouting } else { - this.dimension = new Dimension(width, height!); + this._contentDimension = new Dimension(width, height!); } // Layout contents - super.layout(this.dimension.width, this.dimension.height); + super.layout(this._contentDimension.width, this._contentDimension.height); // Layout composite bar this.layoutCompositeBar(); } private layoutCompositeBar(): void { - if (this.dimension) { - let availableWidth = this.dimension.width - 40; // take padding into account + if (this._contentDimension) { + let availableWidth = this._contentDimension.width - 40; // take padding into account if (this.toolBar) { availableWidth = Math.max(PanelPart.MIN_COMPOSITE_BAR_WIDTH, availableWidth - this.getToolbarWidth()); // adjust height for global actions showing } @@ -522,4 +532,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IPanelService, PanelPart); \ No newline at end of file +registerSingleton(IPanelService, PanelPart); diff --git a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts index 67be38c9e0..080c23eac4 100644 --- a/src/vs/workbench/browser/parts/quickinput/quickInputList.ts +++ b/src/vs/workbench/browser/parts/quickinput/quickInputList.ts @@ -252,7 +252,7 @@ export class QuickInputList { setRowLineHeight: false, multipleSelectionSupport: false, horizontalScrolling: false - } as IListOptions) as WorkbenchList; + } as IListOptions); this.list.getHTMLElement().id = id; this.disposables.push(this.list); this.disposables.push(this.list.onKeyDown(e => { diff --git a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts index 1cfc9cbb89..0c94ff55f6 100644 --- a/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts +++ b/src/vs/workbench/browser/parts/sidebar/sidebarPart.ts @@ -47,6 +47,22 @@ export class SidebarPart extends CompositePart implements IViewletServi readonly snap = true; + get preferredWidth(): number | undefined { + const viewlet = this.getActiveViewlet(); + + if (!viewlet) { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + const width = viewlet.getOptimalWidth(); + + if (typeof width !== 'number') { + return undefined; // {{SQL CARBON EDIT}} strict-null-check + } + + return width; + } + //#endregion get onDidViewletRegister(): Event { return >this.viewletRegistry.onDidRegister; } @@ -303,4 +319,4 @@ registry.registerWorkbenchAction(new SyncActionDescriptor(FocusSideBarAction, Fo primary: KeyMod.CtrlCmd | KeyCode.KEY_0 }), 'View: Focus into Side Bar', nls.localize('viewCategory', "View")); -registerSingleton(IViewletService, SidebarPart); \ No newline at end of file +registerSingleton(IViewletService, SidebarPart); diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 2899cca095..1a97680666 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -611,6 +611,7 @@ export class StatusbarPart extends Part implements IStatusbarService { } layout(width: number, height: number): void { + super.layout(width, height); super.layoutContents(width, height); } @@ -816,4 +817,4 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => { } }); -registerSingleton(IStatusbarService, StatusbarPart); \ No newline at end of file +registerSingleton(IStatusbarService, StatusbarPart); diff --git a/src/vs/workbench/browser/parts/views/customView.ts b/src/vs/workbench/browser/parts/views/customView.ts index c822385c0b..63391a9222 100644 --- a/src/vs/workbench/browser/parts/views/customView.ts +++ b/src/vs/workbench/browser/parts/views/customView.ts @@ -385,13 +385,17 @@ export class CustomTreeView extends Disposable implements ITreeView { collapseByDefault: (e: ITreeItem): boolean => { return e.collapsibleState !== TreeItemCollapsibleState.Expanded; } - }) as WorkbenchAsyncDataTree); + })); aligner.tree = this.tree; this.tree.contextKeyService.createKey(this.id, true); this._register(this.tree.onContextMenu(e => this.onContextMenu(treeMenus, e))); this._register(this.tree.onDidChangeSelection(e => this._onDidChangeSelection.fire(e.elements))); this._register(this.tree.onDidChangeCollapseState(e => { + if (!e.node.element) { + return; + } + const element: ITreeItem = Array.isArray(e.node.element.element) ? e.node.element.element[0] : e.node.element.element; if (e.node.collapsed) { this._onDidCollapseItem.fire(element); diff --git a/src/vs/workbench/browser/parts/views/views.ts b/src/vs/workbench/browser/parts/views/views.ts index 9e5a11312b..15bc731c2a 100644 --- a/src/vs/workbench/browser/parts/views/views.ts +++ b/src/vs/workbench/browser/parts/views/views.ts @@ -238,6 +238,9 @@ export class ContributableViewsModel extends Disposable { private _onDidMove = this._register(new Emitter<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }>()); readonly onDidMove: Event<{ from: IViewDescriptorRef; to: IViewDescriptorRef; }> = this._onDidMove.event; + private _onDidChangeViewState = this._register(new Emitter()); + protected readonly onDidChangeViewState: Event = this._onDidChangeViewState.event; + constructor( container: ViewContainer, viewsService: IViewsService, @@ -301,8 +304,11 @@ export class ContributableViewsModel extends Disposable { } setCollapsed(id: string, collapsed: boolean): void { - const { state } = this.find(id); - state.collapsed = collapsed; + const { index, state, viewDescriptor } = this.find(id); + if (state.collapsed !== collapsed) { + state.collapsed = collapsed; + this._onDidChangeViewState.fire({ viewDescriptor, index }); + } } getSize(id: string): number | undefined { @@ -316,8 +322,11 @@ export class ContributableViewsModel extends Disposable { } setSize(id: string, size: number): void { - const { state } = this.find(id); - state.size = size; + const { index, state, viewDescriptor } = this.find(id); + if (state.size !== size) { + state.size = size; + this._onDidChangeViewState.fire({ viewDescriptor, index }); + } } move(from: string, to: string): void { @@ -474,12 +483,15 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { this.hiddenViewsStorageId = hiddenViewsStorageId; this.storageService = storageService; - this._register(this.onDidAdd(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); - this._register(this.onDidRemove(viewDescriptorRefs => this.saveVisibilityStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); - this._register(this.storageService.onWillSaveState(() => this.saveViewsStates())); + this._register(Event.any( + this.onDidAdd, + this.onDidRemove, + Event.map(this.onDidMove, ({ from, to }) => [from, to]), + Event.map(this.onDidChangeViewState, viewDescriptorRef => [viewDescriptorRef])) + (viewDescriptorRefs => this.saveViewsStates(viewDescriptorRefs.map(r => r.viewDescriptor)))); } - private saveViewsStates(): void { + private saveViewsStates(viewDescriptors: IViewDescriptor[]): void { const storedViewsStates: { [id: string]: { collapsed: boolean, size?: number, order?: number } } = {}; let hasState = false; @@ -496,6 +508,8 @@ export class PersistentContributableViewsModel extends ContributableViewsModel { } else { this.storageService.remove(this.viewletStateStorageId, StorageScope.WORKSPACE); } + + this.saveVisibilityStates(viewDescriptors); } private saveVisibilityStates(viewDescriptors: IViewDescriptor[]): void { @@ -725,4 +739,4 @@ export function createFileIconThemableTreeContainerScope(container: HTMLElement, return themeService.onDidFileIconThemeChange(onDidChangeFileIconTheme); } -registerSingleton(IViewsService, ViewsService); \ No newline at end of file +registerSingleton(IViewsService, ViewsService); diff --git a/src/vs/workbench/browser/parts/views/viewsViewlet.ts b/src/vs/workbench/browser/parts/views/viewsViewlet.ts index 5f52febd27..1091615533 100644 --- a/src/vs/workbench/browser/parts/views/viewsViewlet.ts +++ b/src/vs/workbench/browser/parts/views/viewsViewlet.ts @@ -263,13 +263,11 @@ export abstract class ViewContainerViewlet extends PanelViewlet implements IView private toggleViewVisibility(viewId: string): void { const visible = !this.viewsModel.isVisible(viewId); - /* __GDPR__ - "views.toggleVisibility" : { - "viewId" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "visible": { "classification": "SystemMetaData", "purpose": "FeatureInsight" } - } - */ - this.telemetryService.publicLog('views.toggledVisibility', { viewId, visible }); + type ViewsToggleVisibilityClassification = { + viewId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + visible: { classification: 'SystemMetaData', purpose: 'FeatureInsight' }; + }; + this.telemetryService.publicLog2<{ viewId: String, visible: boolean }, ViewsToggleVisibilityClassification>('views.toggleVisibility', { viewId, visible }); this.viewsModel.setVisible(viewId, visible); } diff --git a/src/vs/workbench/browser/web.main.ts b/src/vs/workbench/browser/web.main.ts index 5f22607a37..bdddf9d7e5 100644 --- a/src/vs/workbench/browser/web.main.ts +++ b/src/vs/workbench/browser/web.main.ts @@ -135,7 +135,7 @@ class CodeRendererMain extends Disposable { serviceCollection.set(ISignService, signService); // Remote Agent - const remoteAgentService = this._register(new RemoteAgentService(environmentService, productService, remoteAuthorityResolverService, signService)); + const remoteAgentService = this._register(new RemoteAgentService(this.configuration.webSocketFactory, environmentService, productService, remoteAuthorityResolverService, signService)); serviceCollection.set(IRemoteAgentService, remoteAgentService); // Files diff --git a/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg b/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg deleted file mode 100644 index 21058f74e7..0000000000 --- a/src/vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts index bc554177d2..8cb6e813fb 100644 --- a/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts +++ b/src/vs/workbench/contrib/codeEditor/browser/toggleWordWrap.ts @@ -288,7 +288,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('unwrapMinified', "Disable wrapping for this file"), - iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg')) } + iconLocation: { + dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + } }, group: 'navigation', order: 1, @@ -302,7 +305,10 @@ MenuRegistry.appendMenuItem(MenuId.EditorTitle, { command: { id: TOGGLE_WORD_WRAP_ID, title: nls.localize('wrapMinified', "Enable wrapping for this file"), - iconLocation: { dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/WordWrap_16x.svg')) } + iconLocation: { + dark: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg')), + light: URI.parse(require.toUrl('vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg')) + } }, group: 'navigation', order: 1, diff --git a/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg new file mode 100644 index 0000000000..f54d621127 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg new file mode 100644 index 0000000000..6a8e3fdf93 --- /dev/null +++ b/src/vs/workbench/contrib/codeEditor/browser/word-wrap-light.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/vs/workbench/contrib/comments/browser/commentNode.ts b/src/vs/workbench/contrib/comments/browser/commentNode.ts index 55be40be18..90931e52de 100644 --- a/src/vs/workbench/contrib/comments/browser/commentNode.ts +++ b/src/vs/workbench/contrib/comments/browser/commentNode.ts @@ -28,7 +28,7 @@ import { AnchorAlignment } from 'vs/base/browser/ui/contextview/contextview'; import { ToggleReactionsAction, ReactionAction, ReactionActionViewItem } from './reactionsAction'; import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; import { ICommentThreadWidget } from 'vs/workbench/contrib/comments/common/commentThreadWidget'; -import { MenuItemAction, SubmenuItemAction } from 'vs/platform/actions/common/actions'; +import { MenuItemAction, SubmenuItemAction, IMenu } from 'vs/platform/actions/common/actions'; import { ContextAwareMenuEntryActionViewItem } from 'vs/platform/actions/browser/menuEntryActionViewItem'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; @@ -54,7 +54,7 @@ export class CommentNode extends Disposable { private _commentContextValue: IContextKey; protected actionRunner?: IActionRunner; - protected toolbar: ToolBar; + protected toolbar: ToolBar | undefined; private _commentFormActions: CommentFormActions; private _onDidDelete = new Emitter(); @@ -134,14 +134,54 @@ export class CommentNode extends Disposable { this.createActionsToolbar(); } + private getToolbarActions(menu: IMenu): { primary: IAction[], secondary: IAction[] } { + const contributedActions = menu.getActions({ shouldForwardArgs: true }); + const primary: IAction[] = []; + const secondary: IAction[] = []; + const result = { primary, secondary }; + fillInActions(contributedActions, result, false, g => /^inline/.test(g)); + return result; + } + + private createToolbar() { + this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { + actionViewItemProvider: action => { + if (action.id === ToggleReactionsAction.ID) { + return new DropdownMenuActionViewItem( + action, + (action).menuActions, + this.contextMenuService, + action => { + return this.actionViewItemProvider(action as Action); + }, + this.actionRunner!, + undefined, + 'toolbar-toggle-pickReactions', + () => { return AnchorAlignment.RIGHT; } + ); + } + return this.actionViewItemProvider(action as Action); + }, + orientation: ActionsOrientation.HORIZONTAL + }); + + this.toolbar.context = { + thread: this.commentThread, + commentUniqueId: this.comment.uniqueIdInThread, + $mid: 9 + }; + + this.registerActionBarListeners(this._actionsToolbarContainer); + this._register(this.toolbar); + } + private createActionsToolbar() { const actions: IAction[] = []; - const secondaryActions: IAction[] = []; let hasReactionHandler = this.commentService.hasReactionHandler(this.owner); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(this.comment.commentReactions || []); actions.push(toggleReactionAction); } @@ -149,60 +189,26 @@ export class CommentNode extends Disposable { const menu = commentMenus.getCommentTitleActions(this.comment, this._contextKeyService); this._register(menu); this._register(menu.onDidChange(e => { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - this.toolbar.setActions(primary, secondary); + const { primary, secondary } = this.getToolbarActions(menu); + if (!this.toolbar && (primary.length || secondary.length)) { + this.createToolbar(); + } + + this.toolbar!.setActions(primary, secondary)(); })); - const contributedActions = menu.getActions({ shouldForwardArgs: true }); - { - const primary: IAction[] = []; - const secondary: IAction[] = []; - const result = { primary, secondary }; - fillInActions(contributedActions, result, false, g => /^inline/.test(g)); - actions.push(...primary); - secondaryActions.push(...secondary); - } + const { primary, secondary } = this.getToolbarActions(menu); + actions.push(...primary); - if (actions.length || secondaryActions.length) { - this.toolbar = new ToolBar(this._actionsToolbarContainer, this.contextMenuService, { - actionViewItemProvider: action => { - if (action.id === ToggleReactionsAction.ID) { - return new DropdownMenuActionViewItem( - action, - (action).menuActions, - this.contextMenuService, - action => { - return this.actionViewItemProvider(action as Action); - }, - this.actionRunner!, - undefined, - 'toolbar-toggle-pickReactions', - () => { return AnchorAlignment.RIGHT; } - ); - } - return this.actionViewItemProvider(action as Action); - }, - orientation: ActionsOrientation.HORIZONTAL - }); - - this.toolbar.context = { - thread: this.commentThread, - commentUniqueId: this.comment.uniqueIdInThread, - $mid: 9 - }; - - this.registerActionBarListeners(this._actionsToolbarContainer); - this.toolbar.setActions(actions, secondaryActions)(); - this._register(this.toolbar); + if (actions.length || secondary.length) { + this.createToolbar(); + this.toolbar!.setActions(actions, secondary)(); } } actionViewItemProvider(action: Action) { let options = {}; - if (action.id === 'comment.delete' || action.id === 'comment.edit' || action.id === ToggleReactionsAction.ID) { + if (action.id === ToggleReactionsAction.ID) { options = { label: false, icon: true }; } else { options = { label: false, icon: true }; @@ -220,7 +226,7 @@ export class CommentNode extends Disposable { } } - private createReactionPicker2(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { + private createReactionPicker(reactionGroup: modes.CommentReaction[]): ToggleReactionsAction { let toggleReactionActionViewItem: DropdownMenuActionViewItem; let toggleReactionAction = this._register(new ToggleReactionsAction(() => { if (toggleReactionActionViewItem) { @@ -315,14 +321,8 @@ export class CommentNode extends Disposable { }); if (hasReactionHandler) { - let toggleReactionAction = this.createReactionPicker2(this.comment.commentReactions || []); + let toggleReactionAction = this.createReactionPicker(this.comment.commentReactions || []); this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); - } else { - // let reactionGroup = this.commentService.getReactionGroup(this.owner); - // if (reactionGroup && reactionGroup.length) { - // let toggleReactionAction = this.createReactionPicker2(reactionGroup || []); - // this._reactionsActionBar.push(toggleReactionAction, { label: false, icon: true }); - // } } } @@ -520,4 +520,4 @@ function fillInActions(groups: [string, Array 'checkbox', isChecked: (breakpoint: IEnablement) => breakpoint.enabled } - }) as WorkbenchList; + }); CONTEXT_BREAKPOINTS_FOCUSED.bindTo(this.list.contextKeyService); diff --git a/src/vs/workbench/contrib/debug/browser/callStackView.ts b/src/vs/workbench/contrib/debug/browser/callStackView.ts index f25a20c387..da4fb562b6 100644 --- a/src/vs/workbench/contrib/debug/browser/callStackView.ts +++ b/src/vs/workbench/contrib/debug/browser/callStackView.ts @@ -145,7 +145,7 @@ export class CallStackView extends ViewletPanel { return nls.localize('showMoreStackFrames2', "Show More Stack Frames"); } } - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService.getModel()).then(undefined, onUnexpectedError); diff --git a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts index 454f5f1759..b372a59234 100644 --- a/src/vs/workbench/contrib/debug/browser/debug.contribution.ts +++ b/src/vs/workbench/contrib/debug/browser/debug.contribution.ts @@ -539,7 +539,7 @@ MenuRegistry.appendMenuItem(MenuId.MenubarDebugMenu, { // Touch Bar if (isMacintosh) { - const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr, icon: string) => { + const registerTouchBarEntry = (id: string, title: string, order: number, when: ContextKeyExpr | undefined, icon: string) => { MenuRegistry.appendMenuItem(MenuId.TouchBarContext, { command: { id, diff --git a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts index 6ae4576b9d..415c6a2a97 100644 --- a/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts +++ b/src/vs/workbench/contrib/debug/browser/debugConfigurationManager.ts @@ -21,7 +21,7 @@ import { IFileService } from 'vs/platform/files/common/files'; import { IWorkspaceContextService, IWorkspaceFolder, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { ICommandService } from 'vs/platform/commands/common/commands'; -import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, ITerminalSettings, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; +import { IDebugConfigurationProvider, ICompound, IDebugConfiguration, IConfig, IGlobalConfig, IConfigurationManager, ILaunch, IDebugAdapterDescriptorFactory, IDebugAdapter, IDebugSession, IAdapterDescriptor, CONTEXT_DEBUG_CONFIGURATION_TYPE, IDebugAdapterFactory, IDebugService } from 'vs/workbench/contrib/debug/common/debug'; import { Debugger } from 'vs/workbench/contrib/debug/common/debugger'; import { IEditorService, ACTIVE_GROUP, SIDE_GROUP } from 'vs/workbench/services/editor/common/editorService'; import { isCodeEditor } from 'vs/editor/browser/editorBrowser'; @@ -108,10 +108,10 @@ export class ConfigurationManager implements IConfigurationManager { return Promise.resolve(config); } - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise { + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise { let tl = this.debugAdapterFactories.get(debugType); if (tl) { - return tl.runInTerminal(args, config); + return tl.runInTerminal(args); } return Promise.resolve(void 0); } diff --git a/src/vs/workbench/contrib/debug/browser/debugHover.ts b/src/vs/workbench/contrib/debug/browser/debugHover.ts index 994f93fa49..6e0a999ae7 100644 --- a/src/vs/workbench/contrib/debug/browser/debugHover.ts +++ b/src/vs/workbench/contrib/debug/browser/debugHover.ts @@ -80,7 +80,7 @@ export class DebugHoverWidget implements IContentWidget { accessibilityProvider: new DebugHoverAccessibilityProvider(), mouseSupport: false, horizontalScrolling: true - }) as any as AsyncDataTree; + }); this.valueContainer = $('.value'); this.valueContainer.tabIndex = 0; diff --git a/src/vs/workbench/contrib/debug/browser/debugSession.ts b/src/vs/workbench/contrib/debug/browser/debugSession.ts index 45e80a936f..d2a01b4721 100644 --- a/src/vs/workbench/contrib/debug/browser/debugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/debugSession.ts @@ -31,7 +31,6 @@ import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet'; import { ReplModel } from 'vs/workbench/contrib/debug/common/replModel'; import { onUnexpectedError } from 'vs/base/common/errors'; import { INotificationService } from 'vs/platform/notification/common/notification'; -import { ISignService } from 'vs/platform/sign/common/sign'; export class DebugSession implements IDebugSession { @@ -66,7 +65,6 @@ export class DebugSession implements IDebugSession { @IViewletService private readonly viewletService: IViewletService, @IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService, @INotificationService private readonly notificationService: INotificationService, - @ISignService private readonly signService: ISignService, @IProductService private readonly productService: IProductService, @IWindowsService private readonly windowsService: IWindowsService ) { @@ -169,7 +167,7 @@ export class DebugSession implements IDebugSession { return dbgr.createDebugAdapter(this).then(debugAdapter => { - this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.signService, this.windowsService); + this.raw = new RawDebugSession(debugAdapter, dbgr, this.telemetryService, customTelemetryService, this.windowsService); return this.raw!.start().then(() => { diff --git a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts index 7a79130873..96ec009227 100644 --- a/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts +++ b/src/vs/workbench/contrib/debug/browser/loadedScriptsView.ts @@ -433,7 +433,7 @@ export class LoadedScriptsView extends ViewletPanel { accessibilityProvider: new LoadedSciptsAccessibilityProvider(), ariaLabel: nls.localize({ comment: ['Debug is a noun in this context, not a verb.'], key: 'loadedScriptsAriaLabel' }, "Debug Loaded Scripts"), } - ) as WorkbenchAsyncDataTree; + ); this.tree.setInput(root); diff --git a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts index 0e11197012..793c849c93 100644 --- a/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts +++ b/src/vs/workbench/contrib/debug/browser/rawDebugSession.ts @@ -12,7 +12,6 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { formatPII, isUri } from 'vs/workbench/contrib/debug/common/debugUtils'; import { IDebugAdapter, IConfig, AdapterEndEvent, IDebugger } from 'vs/workbench/contrib/debug/common/debug'; import { createErrorWithActions } from 'vs/base/common/errorsWithActions'; -import { ISignService } from 'vs/platform/sign/common/sign'; import { ParsedArgs } from 'vs/platform/environment/common/environment'; import { IWindowsService } from 'vs/platform/windows/common/windows'; import { URI } from 'vs/base/common/uri'; @@ -74,7 +73,6 @@ export class RawDebugSession { dbgr: IDebugger, private readonly telemetryService: ITelemetryService, public readonly customTelemetryService: ITelemetryService | undefined, - private readonly signService: ISignService, private readonly windowsService: IWindowsService ) { @@ -548,19 +546,6 @@ export class RawDebugSession { safeSendResponse(response); }); break; - case 'handshake': - try { - const signature = await this.signService.sign(request.arguments.value); - response.body = { - signature: signature - }; - safeSendResponse(response); - } catch (e) { - response.success = false; - response.message = e.message; - safeSendResponse(response); - } - break; default: response.success = false; response.message = `unknown request '${request.command}'`; @@ -602,7 +587,13 @@ export class RawDebugSession { } } else { - args._.push(a2); + const match = /^--(.+)$/.exec(a2); + if (match && match.length === 2) { + const key = match[1]; + (args)[key] = true; + } else { + args._.push(a2); + } } } } diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 37133be750..e0e46cf83e 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -378,12 +378,19 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati this.replDelegate = new ReplDelegate(this.configurationService); const wordWrap = this.configurationService.getValue('debug').console.wordWrap; dom.toggleClass(treeContainer, 'word-wrap', wordWrap); - this.tree = this.instantiationService.createInstance(WorkbenchAsyncDataTree, treeContainer, this.replDelegate, [ - this.instantiationService.createInstance(VariablesRenderer), - this.instantiationService.createInstance(ReplSimpleElementsRenderer), - new ReplExpressionsRenderer(), - new ReplRawObjectsRenderer() - ], new ReplDataSource(), { + this.tree = this.instantiationService.createInstance( + WorkbenchAsyncDataTree, + treeContainer, + this.replDelegate, + [ + this.instantiationService.createInstance(VariablesRenderer), + this.instantiationService.createInstance(ReplSimpleElementsRenderer), + new ReplExpressionsRenderer(), + new ReplRawObjectsRenderer() + ], + // https://github.com/microsoft/TypeScript/issues/32526 + new ReplDataSource() as IAsyncDataSource, + { ariaLabel: nls.localize('replAriaLabel', "Read Eval Print Loop Panel"), accessibilityProvider: new ReplAccessibilityProvider(), identityProvider: { getId: (element: IReplElement) => element.getId() }, @@ -392,7 +399,7 @@ export class Repl extends Panel implements IPrivateReplService, IHistoryNavigati horizontalScrolling: !wordWrap, setRowLineHeight: false, supportDynamicHeights: wordWrap - }) as WorkbenchAsyncDataTree; + }); this._register(this.tree.onContextMenu(e => this.onContextMenu(e))); let lastSelectedString: string; this._register(this.tree.onMouseClick(() => { diff --git a/src/vs/workbench/contrib/debug/browser/variablesView.ts b/src/vs/workbench/contrib/debug/browser/variablesView.ts index f070a4b8d6..a6751f7108 100644 --- a/src/vs/workbench/contrib/debug/browser/variablesView.ts +++ b/src/vs/workbench/contrib/debug/browser/variablesView.ts @@ -91,7 +91,7 @@ export class VariablesView extends ViewletPanel { accessibilityProvider: new VariablesAccessibilityProvider(), identityProvider: { getId: (element: IExpression | IScope) => element.getId() }, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression | IScope) => e } - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService.getViewModel()).then(null, onUnexpectedError); diff --git a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts index ced6bab57d..9f7c22bab3 100644 --- a/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts +++ b/src/vs/workbench/contrib/debug/browser/watchExpressionsView.ts @@ -66,7 +66,7 @@ export class WatchExpressionsView extends ViewletPanel { identityProvider: { getId: (element: IExpression) => element.getId() }, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IExpression) => e }, dnd: new WatchExpressionsDragAndDrop(this.debugService), - }) as WorkbenchAsyncDataTree; + }); this.tree.setInput(this.debugService).then(undefined, onUnexpectedError); CONTEXT_WATCH_EXPRESSIONS_FOCUSED.bindTo(this.tree.contextKeyService); diff --git a/src/vs/workbench/contrib/debug/common/debug.ts b/src/vs/workbench/contrib/debug/common/debug.ts index ed4313e07f..621cbe4dc7 100644 --- a/src/vs/workbench/contrib/debug/common/debug.ts +++ b/src/vs/workbench/contrib/debug/common/debug.ts @@ -24,9 +24,7 @@ import { IViewContainersRegistry, ViewContainer, Extensions as ViewContainerExte import { Registry } from 'vs/platform/registry/common/platform'; import { TaskIdentifier } from 'vs/workbench/contrib/tasks/common/tasks'; import { TelemetryService } from 'vs/platform/telemetry/common/telemetryService'; -import { ITerminalConfiguration } from 'vs/workbench/contrib/terminal/common/terminal'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; -import { IExternalTerminalSettings } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; export const VIEWLET_ID = 'workbench.view.debug'; export const VIEW_CONTAINER: ViewContainer = Registry.as(ViewContainerExtensions.ViewContainersRegistry).registerViewContainer(VIEWLET_ID); @@ -573,12 +571,7 @@ export interface IDebugAdapterTrackerFactory { } export interface ITerminalLauncher { - runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; -} - -export interface ITerminalSettings { - external: IExternalTerminalSettings; - integrated: ITerminalConfiguration; + runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface IConfigurationManager { @@ -623,7 +616,7 @@ export interface IConfigurationManager { createDebugAdapter(session: IDebugSession): IDebugAdapter | undefined; substituteVariables(debugType: string, folder: IWorkspaceFolder | undefined, config: IConfig): Promise; - runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): Promise; + runInTerminal(debugType: string, args: DebugProtocol.RunInTerminalRequestArguments): Promise; } export interface ILaunch { diff --git a/src/vs/workbench/contrib/debug/common/debugger.ts b/src/vs/workbench/contrib/debug/common/debugger.ts index 364ed22282..a9dd2d0c29 100644 --- a/src/vs/workbench/contrib/debug/common/debugger.ts +++ b/src/vs/workbench/contrib/debug/common/debugger.ts @@ -9,7 +9,7 @@ import * as objects from 'vs/base/common/objects'; import { isObject } from 'vs/base/common/types'; import { IJSONSchema, IJSONSchemaSnippet } from 'vs/base/common/jsonSchema'; import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; -import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, ITerminalSettings, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; +import { IConfig, IDebuggerContribution, INTERNAL_CONSOLE_OPTIONS_SCHEMA, IConfigurationManager, IDebugAdapter, IDebugger, IDebugSession, IDebugHelperService } from 'vs/workbench/contrib/debug/common/debug'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver'; import * as ConfigurationResolverUtils from 'vs/workbench/services/configurationResolver/common/configurationResolverUtils'; @@ -108,8 +108,7 @@ export class Debugger implements IDebugger { } runInTerminal(args: DebugProtocol.RunInTerminalRequestArguments): Promise { - const config = this.configurationService.getValue('terminal'); - return this.configurationManager.runInTerminal(this.type, args, config); + return this.configurationManager.runInTerminal(this.type, args); } get label(): string { diff --git a/src/vs/workbench/contrib/debug/node/telemetryApp.ts b/src/vs/workbench/contrib/debug/node/telemetryApp.ts index be09df93e5..ca8004b0f0 100644 --- a/src/vs/workbench/contrib/debug/node/telemetryApp.ts +++ b/src/vs/workbench/contrib/debug/node/telemetryApp.ts @@ -8,7 +8,7 @@ import { AppInsightsAppender } from 'vs/platform/telemetry/node/appInsightsAppen import { TelemetryAppenderChannel } from 'vs/platform/telemetry/node/telemetryIpc'; const appender = new AppInsightsAppender(process.argv[2], JSON.parse(process.argv[3]), process.argv[4]); -process.once('exit', () => appender.dispose()); +process.once('exit', () => appender.flush()); const channel = new TelemetryAppenderChannel(appender); const server = new Server('telemetry'); diff --git a/src/vs/workbench/contrib/debug/node/terminals.ts b/src/vs/workbench/contrib/debug/node/terminals.ts index f920961ae7..5683a13f05 100644 --- a/src/vs/workbench/contrib/debug/node/terminals.ts +++ b/src/vs/workbench/contrib/debug/node/terminals.ts @@ -5,15 +5,15 @@ import * as cp from 'child_process'; import * as env from 'vs/base/common/platform'; -import { ITerminalSettings } from 'vs/workbench/contrib/debug/common/debug'; import { getSystemShell } from 'vs/workbench/contrib/terminal/node/terminal'; import { WindowsExternalTerminalService, MacExternalTerminalService, LinuxExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/node/externalTerminalService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IExternalTerminalService } from 'vs/workbench/contrib/externalTerminal/common/externalTerminal'; +import { ExtHostConfigProvider } from 'vs/workbench/api/common/extHostConfiguration'; let externalTerminalService: IExternalTerminalService | undefined = undefined; -export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): void { +export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestArguments, configProvider: ExtHostConfigProvider): void { if (!externalTerminalService) { if (env.isWindows) { externalTerminalService = new WindowsExternalTerminalService(undefined); @@ -24,6 +24,7 @@ export function runInExternalTerminal(args: DebugProtocol.RunInTerminalRequestAr } } if (externalTerminalService) { + const config = configProvider.getConfiguration('terminal'); externalTerminalService.runInTerminal(args.title!, args.cwd, args.args, args.env || {}, config.external || {}); } } @@ -60,24 +61,25 @@ export function hasChildProcesses(processId: number): boolean { const enum ShellType { cmd, powershell, bash } -export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, config: ITerminalSettings): string { +export function prepareCommand(args: DebugProtocol.RunInTerminalRequestArguments, shell: string, configProvider: ExtHostConfigProvider): string { - let shellType: ShellType; + let shellType = env.isWindows ? ShellType.cmd : ShellType.bash; // pick a good default - // get the shell configuration for the current platform - let shell: string; - const shell_config = config.integrated.shell; - if (env.isWindows) { - shell = shell_config.windows || getSystemShell(env.Platform.Windows); - shellType = ShellType.cmd; - } else if (env.isLinux) { - shell = shell_config.linux || getSystemShell(env.Platform.Linux); - shellType = ShellType.bash; - } else if (env.isMacintosh) { - shell = shell_config.osx || getSystemShell(env.Platform.Mac); - shellType = ShellType.bash; - } else { - throw new Error('Unknown platform'); + if (shell) { + + const config = configProvider.getConfiguration('terminal'); + + // get the shell configuration for the current platform + const shell_config = config.integrated.shell; + if (env.isWindows) { + shell = shell_config.windows || getSystemShell(env.Platform.Windows); + } else if (env.isLinux) { + shell = shell_config.linux || getSystemShell(env.Platform.Linux); + } else if (env.isMacintosh) { + shell = shell_config.osx || getSystemShell(env.Platform.Mac); + } else { + throw new Error('Unknown platform'); + } } // try to determine the shell type diff --git a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts index 80afc8d853..746770664f 100644 --- a/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts +++ b/src/vs/workbench/contrib/debug/test/browser/debugModel.test.ts @@ -15,7 +15,7 @@ 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!, undefined!, undefined!); + return new DebugSession({ resolved: { name, type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, parentSession, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); } suite('Debug - Model', () => { @@ -427,7 +427,7 @@ suite('Debug - Model', () => { // Repl output test('repl output', () => { - const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); + const session = new DebugSession({ resolved: { name: 'mockSession', type: 'node', request: 'launch' }, unresolved: undefined }, undefined!, model, undefined, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!, undefined!); const repl = new ReplModel(session); repl.appendToRepl('first line\n', severity.Error); repl.appendToRepl('second line ', severity.Error); diff --git a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts index a75927c615..9e605f0ae8 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts @@ -44,6 +44,7 @@ import { ExtensionDependencyChecker } from 'vs/workbench/contrib/extensions/brow import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { RemoteExtensionsInstaller } from 'vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller'; // Singletons registerSingleton(IExtensionsWorkbenchService, ExtensionsWorkbenchService); @@ -188,12 +189,16 @@ Registry.as(ConfigurationExtensions.Configuration) description: localize('extensionsCloseExtensionDetailsOnViewChange', "When enabled, editors with extension details will be automatically closed upon navigating away from the Extensions View."), default: false }, - // {{SQL CARBON EDIT}} - 'extensions.extensionsPolicy': { + 'extensions.extensionsPolicy': { // {{SQL CARBON EDIT}} type: 'string', description: localize('extensionsPolicy', "Sets the security policy for downloading extensions."), scope: ConfigurationScope.APPLICATION, default: ExtensionsPolicy.allowAll + }, + 'extensions.confirmedUriHandlerExtensionIds': { + type: 'array', + description: localize('handleUriConfirmedExtensions', "When an extension is listed here, a confirmation prompt will not be shown when that extension handles a URI."), + default: [] } } }); @@ -379,3 +384,4 @@ workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting); workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually); workbenchRegistry.registerWorkbenchContribution(ExtensionDependencyChecker, LifecyclePhase.Eventually); +workbenchRegistry.registerWorkbenchContribution(RemoteExtensionsInstaller, LifecyclePhase.Eventually); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts index 874c3ac42c..dd0a3cd283 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsActions.ts @@ -62,6 +62,7 @@ import { ITextFileService } from 'vs/workbench/services/textfile/common/textfile import { IProductService } from 'vs/platform/product/common/product'; import { IClipboardService } from 'vs/platform/clipboard/common/clipboardService'; import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs'; +import { IProgressService, ProgressLocation } from 'vs/platform/progress/common/progress'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; // {{SQL CARBON EDIT}} @@ -287,7 +288,7 @@ export class InstallAction extends ExtensionAction { } } -export class InstallInOtherServerAction extends ExtensionAction { +export abstract class InstallInOtherServerAction extends ExtensionAction { protected static INSTALL_LABEL = localize('install', "Install"); protected static INSTALLING_LABEL = localize('installing', "Installing"); @@ -296,7 +297,6 @@ export class InstallInOtherServerAction extends ExtensionAction { private static readonly InstallingClass = 'extension-action install installing'; updateWhenCounterExtensionChanges: boolean = true; - protected installing: boolean = false; constructor( id: string, @@ -304,70 +304,63 @@ export class InstallInOtherServerAction extends ExtensionAction { @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, ) { super(id, InstallInOtherServerAction.INSTALL_LABEL, InstallInOtherServerAction.Class, false); - this.updateLabel(); this.update(); } - private updateLabel(): void { - this.label = this.getLabel(); - this.tooltip = this.label; - } - - protected getLabel(): string { - return this.installing ? InstallInOtherServerAction.INSTALLING_LABEL : - this.server ? `${InstallInOtherServerAction.INSTALL_LABEL} on ${this.server.label}` - : InstallInOtherServerAction.INSTALL_LABEL; - - } - update(): void { this.enabled = false; this.class = InstallInOtherServerAction.Class; - if (this.installing) { - this.enabled = true; - this.class = InstallInOtherServerAction.InstallingClass; - this.updateLabel(); - return; - } if ( - this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed + this.extension && this.extension.local && this.server && this.extension.state === ExtensionState.Installed && this.extension.type === ExtensionType.User // disabled by extension kind or it is a language pack extension && (this.extension.enablementState === EnablementState.DisabledByExtensionKind || isLanguagePackExtension(this.extension.local.manifest)) - // Not installed in other server and can install in other server - && !this.extensionsWorkbenchService.installed.some(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server) - && this.extensionsWorkbenchService.canInstall(this.extension) ) { - this.enabled = true; - this.updateLabel(); - return; + const extensionInOtherServer = this.extensionsWorkbenchService.installed.filter(e => areSameExtensions(e.identifier, this.extension.identifier) && e.server === this.server)[0]; + if (extensionInOtherServer) { + // Getting installed in other server + if (extensionInOtherServer.state === ExtensionState.Installing && !extensionInOtherServer.local) { + this.enabled = true; + this.label = InstallInOtherServerAction.INSTALLING_LABEL; + this.class = InstallInOtherServerAction.InstallingClass; + } + } else { + // Not installed in other server + this.enabled = true; + this.label = this.getInstallLabel(); + } } } async run(): Promise { - if (this.server && !this.installing) { - this.installing = true; - this.update(); + if (this.server) { this.extensionsWorkbenchService.open(this.extension); alert(localize('installExtensionStart', "Installing extension {0} started. An editor is now open with more details on this extension", this.extension.displayName)); if (this.extension.gallery) { await this.server.extensionManagementService.installFromGallery(this.extension.gallery); - this.installing = false; - this.update(); + } else { + const vsix = await this.extension.server!.extensionManagementService.zip(this.extension.local!); + await this.server.extensionManagementService.install(vsix); } } } + + protected abstract getInstallLabel(): string; } export class RemoteInstallAction extends InstallInOtherServerAction { constructor( @IExtensionsWorkbenchService extensionsWorkbenchService: IExtensionsWorkbenchService, - @IExtensionManagementServerService extensionManagementServerService: IExtensionManagementServerService + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService ) { super(`extensions.remoteinstall`, extensionManagementServerService.remoteExtensionManagementServer, extensionsWorkbenchService); } + protected getInstallLabel(): string { + return this.extensionManagementServerService.remoteExtensionManagementServer ? localize('Install on Server', "Install on {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label) : InstallInOtherServerAction.INSTALL_LABEL; + } + } export class LocalInstallAction extends InstallInOtherServerAction { @@ -379,8 +372,8 @@ export class LocalInstallAction extends InstallInOtherServerAction { super(`extensions.localinstall`, extensionManagementServerService.localExtensionManagementServer, extensionsWorkbenchService); } - protected getLabel(): string { - return this.installing ? InstallInOtherServerAction.INSTALLING_LABEL : localize('install locally', "Install Locally"); + protected getInstallLabel(): string { + return localize('install locally', "Install Locally"); } } @@ -1220,7 +1213,7 @@ export class ReloadAction extends ExtensionAction { const isSameExtensionRunning = runningExtension && this.extension.server === this.extensionManagementServerService.getExtensionManagementServer(runningExtension.extensionLocation); if (isUninstalled) { - if (isSameExtensionRunning) { + if (isSameExtensionRunning && !this.extensionService.canRemoveExtension(runningExtension)) { this.enabled = true; this.label = localize('reloadRequired', "Reload Required"); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio @@ -1725,7 +1718,7 @@ export class InstallRecommendedExtensionAction extends Action { return this.viewletService.openViewlet(VIEWLET_ID, true) .then(viewlet => viewlet as IExtensionsViewlet) .then(viewlet => { - viewlet.search('@recommended '); + viewlet.search(`@id:${this.extensionId}`); viewlet.focus(); return this.extensionWorkbenchService.queryGallery({ names: [this.extensionId], source: 'install-recommendation', pageSize: 1 }, CancellationToken.None) .then(pager => { @@ -3092,6 +3085,119 @@ export class InstallSpecificVersionOfExtensionAction extends Action { } } +interface IExtensionPickItem extends IQuickPickItem { + extension?: IExtension; +} + +export class InstallLocalExtensionsOnRemoteAction extends Action { + + constructor( + @IExtensionsWorkbenchService private readonly extensionsWorkbenchService: IExtensionsWorkbenchService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @IExtensionGalleryService private readonly extensionGalleryService: IExtensionGalleryService, + @IQuickInputService private readonly quickInputService: IQuickInputService, + @INotificationService private readonly notificationService: INotificationService, + @IWindowService private readonly windowService: IWindowService, + @IProgressService private readonly progressService: IProgressService, + @IInstantiationService private readonly instantiationService: IInstantiationService + ) { + super('workbench.extensions.actions.installLocalExtensionsOnRemote'); + this.update(); + this._register(this.extensionsWorkbenchService.onChange(() => this.update())); + } + + get label(): string { + return this.extensionManagementServerService.remoteExtensionManagementServer ? + localize('install local extensions', "Install Local Extensions on {0}", this.extensionManagementServerService.remoteExtensionManagementServer.label) : ''; + } + + private update(): void { + this.enabled = this.getLocalExtensionsToInstall().length > 0; + } + + private getLocalExtensionsToInstall(): IExtension[] { + return this.extensionsWorkbenchService.local.filter(extension => { + const action = this.instantiationService.createInstance(RemoteInstallAction); + action.extension = extension; + return action.enabled; + }); + } + + async run(): Promise { + this.selectAndInstallLocalExtensions(); + return Promise.resolve(); + } + + private selectAndInstallLocalExtensions(): void { + const quickPick = this.quickInputService.createQuickPick(); + quickPick.busy = true; + const disposable = quickPick.onDidAccept(() => { + disposable.dispose(); + quickPick.hide(); + quickPick.dispose(); + this.onDidAccept(quickPick.selectedItems); + }); + quickPick.show(); + const localExtensionsToInstall = this.getLocalExtensionsToInstall(); + quickPick.busy = false; + if (localExtensionsToInstall.length) { + quickPick.placeholder = localize('select extensions to install', "Select extensions to install"); + quickPick.canSelectMany = true; + localExtensionsToInstall.sort((e1, e2) => e1.displayName.localeCompare(e2.displayName)); + quickPick.items = localExtensionsToInstall.map(extension => ({ extension, label: extension.displayName, description: extension.version })); + } else { + quickPick.hide(); + quickPick.dispose(); + this.notificationService.notify({ + severity: Severity.Info, + message: localize('no local extensions', "There are no extensions to install.") + }); + } + } + + private onDidAccept(selectedItems: ReadonlyArray): void { + if (selectedItems.length) { + const localExtensionsToInstall = selectedItems.filter(r => !!r.extension).map(r => r.extension!); + if (localExtensionsToInstall.length) { + this.progressService.withProgress( + { + location: ProgressLocation.Notification, + title: localize('installing extensions', "Installing Extensions...") + }, + () => this.installLocalExtensions(localExtensionsToInstall)); + } + } + } + + private async installLocalExtensions(localExtensionsToInstall: IExtension[]): Promise { + const galleryExtensions: IGalleryExtension[] = []; + const vsixs: URI[] = []; + await Promise.all(localExtensionsToInstall.map(async extension => { + if (this.extensionGalleryService.isEnabled()) { + const gallery = await this.extensionGalleryService.getCompatibleExtension(extension.identifier, extension.version); + if (gallery) { + galleryExtensions.push(gallery); + return; + } + } + const vsix = await this.extensionManagementServerService.localExtensionManagementServer!.extensionManagementService.zip(extension.local!); + vsixs.push(vsix); + })); + + await Promise.all(galleryExtensions.map(gallery => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.installFromGallery(gallery))); + await Promise.all(vsixs.map(vsix => this.extensionManagementServerService.remoteExtensionManagementServer!.extensionManagementService.install(vsix))); + + this.notificationService.notify({ + severity: Severity.Info, + message: localize('finished installing', "Completed installing the extensions. Please reload the window now."), + actions: { + primary: [new Action('realod', localize('reload', "Realod Window"), '', true, + () => this.windowService.reloadWindow())] + } + }); + } +} + CommandsRegistry.registerCommand('workbench.extensions.action.showExtensionsForLanguage', function (accessor: ServicesAccessor, fileExtension: string) { const viewletService = accessor.get(IViewletService); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts index 7b32f72fbf..22efa0da26 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsViewlet.ts @@ -18,11 +18,11 @@ import { append, $, addClass, toggleClass, Dimension } from 'vs/base/browser/dom import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions'; -import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, ExtensionState, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey, VIEW_CONTAINER } from '../common/extensions'; +import { IExtensionsWorkbenchService, IExtensionsViewlet, VIEWLET_ID, AutoUpdateConfigurationKey, ShowRecommendationsOnlyOnDemandKey, CloseExtensionDetailsOnViewChangeKey, VIEW_CONTAINER } from '../common/extensions'; import { ShowEnabledExtensionsAction, ShowInstalledExtensionsAction, ShowRecommendedExtensionsAction, ShowPopularExtensionsAction, ShowDisabledExtensionsAction, ShowOutdatedExtensionsAction, ClearExtensionsInputAction, ChangeSortAction, UpdateAllAction, CheckForUpdatesAction, DisableAllAction, EnableAllAction, - EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction + EnableAutoUpdateAction, DisableAutoUpdateAction, ShowBuiltInExtensionsAction, InstallVSIXAction, InstallLocalExtensionsOnRemoteAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; import { IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionEnablementService, IExtensionManagementServerService, IExtensionManagementServer } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -32,7 +32,7 @@ import { OpenGlobalSettingsAction } from 'vs/workbench/contrib/preferences/brows import { IProgressService, 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'; +import { IActivityService, NumberBadge } from 'vs/workbench/services/activity/common/activity'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IViewsRegistry, IViewDescriptor, Extensions } from 'vs/workbench/common/views'; @@ -55,7 +55,7 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment' import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { Registry } from 'vs/platform/registry/common/platform'; import { ViewContainerViewlet } from 'vs/workbench/browser/parts/views/viewsViewlet'; -import { RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; +import { RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { ILabelService } from 'vs/platform/label/common/label'; import { MementoObject } from 'vs/workbench/common/memento'; @@ -146,7 +146,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id, name: viewIdNameMappings[id], ctorDescriptor: { ctor: EnabledExtensionsView }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')), weight: 40, canToggleVisibility: true, order: 1 @@ -161,7 +161,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id, name: viewIdNameMappings[id], ctorDescriptor: { ctor: DisabledExtensionsView }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.isEqualTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.isEqualTo('')), weight: 10, canToggleVisibility: true, order: 3, @@ -212,7 +212,7 @@ export class ExtensionsViewletViewsContribution implements IWorkbenchContributio id: `extensions.${server.authority}.default`, get name() { return getInstalledViewName(); }, ctorDescriptor: { ctor: ServerExtensionsView, arguments: [server, EventOf.map(onDidChangeServerLabel, () => getInstalledViewName())] }, - when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteAuthorityContext.notEqualsTo('')), + when: ContextKeyExpr.and(ContextKeyExpr.has('defaultExtensionViews'), ContextKeyExpr.has('hasInstalledExtensions'), RemoteNameContext.notEqualsTo('')), weight: 40, order: 1 }]; @@ -352,6 +352,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio @IInstantiationService instantiationService: IInstantiationService, @IEditorGroupsService private readonly editorGroupService: IEditorGroupsService, @IExtensionManagementService private readonly extensionManagementService: IExtensionManagementService, + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, @INotificationService private readonly notificationService: INotificationService, @IViewletService private readonly viewletService: IViewletService, @IThemeService themeService: IThemeService, @@ -483,6 +484,7 @@ export class ExtensionsViewlet extends ViewContainerViewlet implements IExtensio this.instantiationService.createInstance(CheckForUpdatesAction, CheckForUpdatesAction.ID, CheckForUpdatesAction.LABEL), ...(this.configurationService.getValue(AutoUpdateConfigurationKey) ? [this.instantiationService.createInstance(DisableAutoUpdateAction, DisableAutoUpdateAction.ID, DisableAutoUpdateAction.LABEL)] : [this.instantiationService.createInstance(UpdateAllAction, UpdateAllAction.ID, UpdateAllAction.LABEL), this.instantiationService.createInstance(EnableAutoUpdateAction, EnableAutoUpdateAction.ID, EnableAutoUpdateAction.LABEL)]), this.instantiationService.createInstance(InstallVSIXAction, InstallVSIXAction.ID, InstallVSIXAction.LABEL), + ...(this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer ? [this.instantiationService.createInstance(InstallLocalExtensionsOnRemoteAction)] : []), new Separator(), this.instantiationService.createInstance(DisableAllAction, DisableAllAction.ID, DisableAllAction.LABEL), this.instantiationService.createInstance(EnableAllAction, EnableAllAction.ID, EnableAllAction.LABEL) @@ -635,11 +637,6 @@ export class StatusUpdater extends Disposable implements IWorkbenchContribution private onServiceChange(): void { this.badgeHandle.clear(); - if (this.extensionsWorkbenchService.local.some(e => e.state === ExtensionState.Installing)) { - this.badgeHandle.value = this.activityService.showActivity(VIEWLET_ID, new ProgressBadge(() => localize('extensions', "Extensions")), 'extensions-badge progress-badge'); - return; - } - const outdated = this.extensionsWorkbenchService.outdated.reduce((r, e) => r + (this.extensionEnablementService.isEnabled(e.local!) ? 1 : 0), 0); if (outdated > 0) { const badge = new NumberBadge(outdated, n => localize('outdatedExtensions', '{0} Outdated Extensions', n)); diff --git a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts index 2d5c1593f8..182b19d986 100644 --- a/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +++ b/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -555,6 +555,8 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension this.resetIgnoreAutoUpdateExtensions(); this.eventuallySyncWithGallery(true); }); + + this._register(this.onChange(() => this.updateActivity())); } get local(): IExtension[] { @@ -1082,6 +1084,21 @@ export class ExtensionsWorkbenchService extends Disposable implements IExtension return this._extensionAllowedBadgeProviders; } + private _activityCallBack: (() => void) | null = null; + private updateActivity(): void { + if ((this.localExtensions && this.localExtensions.local.some(e => e.state === ExtensionState.Installing || e.state === ExtensionState.Uninstalling)) + || (this.remoteExtensions && this.remoteExtensions.local.some(e => e.state === ExtensionState.Installing || e.state === ExtensionState.Uninstalling))) { + if (!this._activityCallBack) { + this.progressService.withProgress({ location: ProgressLocation.Extensions }, () => new Promise(c => this._activityCallBack = c)); + } + } else { + if (this._activityCallBack) { + this._activityCallBack(); + } + this._activityCallBack = null; + } + } + private onError(err: any): void { if (isPromiseCanceledError(err)) { return; diff --git a/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts b/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.ts new file mode 100644 index 0000000000..b6e4edf9ba --- /dev/null +++ b/src/vs/workbench/contrib/extensions/browser/remoteExtensionsInstaller.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 { IWorkbenchContribution } from 'vs/workbench/common/contributions'; +import { CommandsRegistry } from 'vs/platform/commands/common/commands'; +import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; +import { localize } from 'vs/nls'; +import { Disposable, toDisposable } from 'vs/base/common/lifecycle'; +import { IExtensionManagementServerService } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; +import { ILabelService } from 'vs/platform/label/common/label'; +import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; +import { InstallLocalExtensionsOnRemoteAction } from 'vs/workbench/contrib/extensions/browser/extensionsActions'; + +export class RemoteExtensionsInstaller extends Disposable implements IWorkbenchContribution { + + constructor( + @IExtensionManagementServerService private readonly extensionManagementServerService: IExtensionManagementServerService, + @ILabelService labelService: ILabelService, + @IInstantiationService instantiationService: IInstantiationService + ) { + super(); + if (this.extensionManagementServerService.localExtensionManagementServer && this.extensionManagementServerService.remoteExtensionManagementServer) { + const installLocalExtensionsOnRemoteAction = instantiationService.createInstance(InstallLocalExtensionsOnRemoteAction); + CommandsRegistry.registerCommand('workbench.extensions.installLocalExtensions', () => installLocalExtensionsOnRemoteAction.run()); + let disposable = Disposable.None; + const appendMenuItem = () => { + disposable.dispose(); + disposable = MenuRegistry.appendMenuItem(MenuId.CommandPalette, { + command: { + id: 'workbench.extensions.installLocalExtensions', + category: localize('extensions', "Extensions"), + title: installLocalExtensionsOnRemoteAction.label + } + }); + }; + appendMenuItem(); + this._register(labelService.onDidChangeFormatters(e => appendMenuItem())); + this._register(toDisposable(() => disposable.dispose())); + } + } + +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts index 1b90d598ca..2ca6604731 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/extensionTipsService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { localize } from 'vs/nls'; -import { join } from 'vs/base/common/path'; +import { join, basename } from 'vs/base/common/path'; import { forEach } from 'vs/base/common/collections'; import { Disposable } from 'vs/base/common/lifecycle'; import { match } from 'vs/base/common/glob'; @@ -44,6 +44,8 @@ import { CancellationToken } from 'vs/base/common/cancellation'; import { ExtensionType } from 'vs/platform/extensions/common/extensions'; import { extname } from 'vs/base/common/resources'; import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; +import { IExeBasedExtensionTip } from 'vs/platform/product/common/product'; +import { timeout } from 'vs/base/common/async'; const milliSecondsInADay = 1000 * 60 * 60 * 24; const choiceNever = localize('neverShowAgain', "Don't Show Again"); @@ -72,9 +74,9 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe _serviceBrand: any; private _fileBasedRecommendations: { [id: string]: { recommendedTime: number, sources: ExtensionRecommendationSource[] }; } = Object.create(null); - // {{SQL CARBON EDIT}} - private _recommendations: string[] = []; - private _exeBasedRecommendations: { [id: string]: string; } = Object.create(null); + private _recommendations: string[] = []; // {{SQL CARBON EDIT}} + private _exeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); + private _importantExeBasedRecommendations: { [id: string]: IExeBasedExtensionTip; } = Object.create(null); private _availableRecommendations: { [pattern: string]: string[] } = Object.create(null); private _allWorkspaceRecommendedExtensions: IExtensionRecommendation[] = []; private _dynamicWorkspaceRecommendations: string[] = []; @@ -188,7 +190,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe forEach(this._exeBasedRecommendations, entry => output[entry.key.toLowerCase()] = { reasonId: ExtensionRecommendationReason.Executable, - reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value) + reasonText: localize('exeBasedRecommendation', "This extension is recommended because you have {0} installed.", entry.value.friendlyName) }); forEach(this._fileBasedRecommendations, entry => output[entry.key.toLowerCase()] = { @@ -504,6 +506,100 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe //#endregion + //#region important exe based extension + + private async promptForImportantExeBasedExtension(): Promise { + + const storageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + const config = this.configurationService.getValue(ConfigurationKey); + + if (config.ignoreRecommendations + || config.showRecommendationsOnlyOnDemand + || this.storageService.getBoolean(storageKey, StorageScope.WORKSPACE, false)) { + return false; + } + + const installed = await this.extensionManagementService.getInstalled(ExtensionType.User); + let recommendationsToSuggest = Object.keys(this._importantExeBasedRecommendations); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); + if (recommendationsToSuggest.length === 0) { + return false; + } + + const id = recommendationsToSuggest[0]; + const tip = this._importantExeBasedRecommendations[id]; + const message = localize('exeRecommended', "The '{0}' extension is recommended as you have {1} installed on your system.", tip.friendlyName!, tip.exeFriendlyName || basename(tip.windowsPath!)); + + this.notificationService.prompt(Severity.Info, message, + [{ + label: localize('install', 'Install'), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'install', extensionId: name }); + this.instantiationService.createInstance(InstallRecommendedExtensionAction, id).run(); + } + }, { + label: localize('showRecommendations', "Show Recommendations"), + run: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations: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: () => { + this.addToImportantRecommendationsIgnore(id); + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations: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: () => this.setIgnoreRecommendationsConfig(true) + }, { + label: localize('no', "No"), + run: () => this.setIgnoreRecommendationsConfig(false) + }] + ); + } + }], + { + sticky: true, + onCancel: () => { + /* __GDPR__ + "exeExtensionRecommendations:popup" : { + "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, + "extensionId": { "classification": "PublicNonPersonalData", "purpose": "FeatureInsight" } + } + */ + this.telemetryService.publicLog('exeExtensionRecommendations:popup', { userReaction: 'cancelled', extensionId: name }); + } + } + ); + + return true; + } + //#region fileBasedRecommendations getFileBasedRecommendations(): IExtensionRecommendation[] { @@ -607,7 +703,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe const now = Date.now(); forEach(this._availableRecommendations, entry => { let { key: pattern, value: ids } = entry; - if (match(pattern, model.uri.path)) { + if (match(pattern, model.uri.toString())) { for (let id of ids) { if (caseInsensitiveGet(product.extensionImportantTips, id)) { recommendationsToSuggest.push(id); @@ -656,21 +752,8 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private async promptRecommendedExtensionForFileType(recommendationsToSuggest: string[], installed: ILocalExtension[]): Promise { - 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; - }); + recommendationsToSuggest = this.filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest, installed); if (recommendationsToSuggest.length === 0) { return false; } @@ -680,22 +763,12 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (!entry) { return false; } - const name = entry['name']; - + 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') { + if (entry.isExtensionPack) { 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'), @@ -728,12 +801,7 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe label: choiceNever, isSecondary: true, run: () => { - importantRecommendationsIgnoreList.push(id); - this.storageService.store( - 'extensionsAssistant/importantRecommendationsIgnore', - JSON.stringify(importantRecommendationsIgnoreList), - StorageScope.GLOBAL - ); + this.addToImportantRecommendationsIgnore(id); /* __GDPR__ "extensionRecommendations:popup" : { "userReaction" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, @@ -746,10 +814,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe localize('ignoreExtensionRecommendations', "Do you want to ignore all extension recommendations?"), [{ label: localize('ignoreAll', "Yes, Ignore All"), - run: () => setIgnoreRecommendationsConfig(true) + run: () => this.setIgnoreRecommendationsConfig(true) }, { label: localize('no', "No"), - run: () => setIgnoreRecommendationsConfig(false) + run: () => this.setIgnoreRecommendationsConfig(false) }] ); } @@ -841,6 +909,42 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe ); } + private filterAllIgnoredInstalledAndNotAllowed(recommendationsToSuggest: string[], installed: ILocalExtension[]): string[] { + + 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()); + return 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; + }); + } + + private addToImportantRecommendationsIgnore(id: string) { + const importantRecommendationsIgnoreList = JSON.parse(this.storageService.get('extensionsAssistant/importantRecommendationsIgnore', StorageScope.GLOBAL, '[]')); + importantRecommendationsIgnoreList.push(id); + this.storageService.store( + 'extensionsAssistant/importantRecommendationsIgnore', + JSON.stringify(importantRecommendationsIgnoreList), + StorageScope.GLOBAL + ); + } + + private setIgnoreRecommendationsConfig(configVal: boolean) { + this.configurationService.updateValue('extensions.ignoreRecommendations', configVal, ConfigurationTarget.USER); + if (configVal) { + const ignoreWorkspaceRecommendationsStorageKey = 'extensionsAssistant/workspaceRecommendationsIgnore'; + this.storageService.store(ignoreWorkspaceRecommendationsStorageKey, true, StorageScope.WORKSPACE); + } + } + //#endregion //#region otherRecommendations @@ -863,18 +967,18 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe } private fetchProactiveRecommendations(calledDuringStartup?: boolean): Promise { - let fetchPromise = Promise.resolve(undefined); + let fetchPromise = Promise.resolve(undefined); if (!this.proactiveRecommendationsFetched) { this.proactiveRecommendationsFetched = true; - // Executable based recommendations carry out a lot of file stats, so run them after 10 secs - // So that the startup is not affected + // Executable based recommendations carry out a lot of file stats, delay the resolution so that the startup is not affected + // 10 sec for regular extensions + // 3 secs for important - fetchPromise = new Promise((c, e) => { - setTimeout(() => { - Promise.all([this.fetchExecutableRecommendations(), this.fetchDynamicWorkspaceRecommendations()]).then(() => c(undefined)); - }, calledDuringStartup ? 10000 : 0); - }); + const importantExeBasedRecommendations = timeout(calledDuringStartup ? 3000 : 0).then(_ => this.fetchExecutableRecommendations(true)); + importantExeBasedRecommendations.then(_ => this.promptForImportantExeBasedExtension()); + + fetchPromise = timeout(calledDuringStartup ? 10000 : 0).then(_ => Promise.all([this.fetchDynamicWorkspaceRecommendations(), this.fetchExecutableRecommendations(false), importantExeBasedRecommendations])); } return fetchPromise; @@ -883,20 +987,22 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe /** * If user has any of the tools listed in product.exeBasedExtensionTips, fetch corresponding recommendations */ - private fetchExecutableRecommendations(): Promise { + private fetchExecutableRecommendations(important: boolean): Promise { const homeDir = os.homedir(); let foundExecutables: Set = new Set(); - let findExecutable = (exeName: string, path: string) => { + let findExecutable = (exeName: string, tip: IExeBasedExtensionTip, path: string) => { return pfs.fileExists(path).then(exists => { if (exists && !foundExecutables.has(exeName)) { foundExecutables.add(exeName); - (product.exeBasedExtensionTips[exeName]['recommendations'] || []) - .forEach(extensionId => { - if (product.exeBasedExtensionTips[exeName]['friendlyName']) { - this._exeBasedRecommendations[extensionId.toLowerCase()] = product.exeBasedExtensionTips[exeName]['friendlyName']; + (tip['recommendations'] || []).forEach(extensionId => { + if (tip.friendlyName) { + if (important) { + this._importantExeBasedRecommendations[extensionId.toLowerCase()] = tip; } - }); + this._exeBasedRecommendations[extensionId.toLowerCase()] = tip; + } + }); } }); }; @@ -907,8 +1013,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe if (typeof entry.value !== 'object' || !Array.isArray(entry.value['recommendations'])) { return; } - - let exeName = entry.key; + if (important !== !!entry.value.important) { + return; + } + const exeName = entry.key; if (process.platform === 'win32') { let windowsPath = entry.value['windowsPath']; if (!windowsPath || typeof windowsPath !== 'string') { @@ -919,10 +1027,10 @@ export class ExtensionTipsService extends Disposable implements IExtensionTipsSe .replace('%ProgramFiles%', process.env['ProgramFiles']!) .replace('%APPDATA%', process.env['APPDATA']!) .replace('%WINDIR%', process.env['WINDIR']!); - promises.push(findExecutable(exeName, windowsPath)); + promises.push(findExecutable(exeName, entry.value, windowsPath)); } else { - promises.push(findExecutable(exeName, join('/usr/local/bin', exeName))); - promises.push(findExecutable(exeName, join(homeDir, exeName))); + promises.push(findExecutable(exeName, entry.value, join('/usr/local/bin', exeName))); + promises.push(findExecutable(exeName, entry.value, join(homeDir, exeName))); } }); diff --git a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts index 9c2ae3c806..0d0ff4715c 100644 --- a/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts +++ b/src/vs/workbench/contrib/extensions/electron-browser/runtimeExtensionsEditor.ts @@ -405,7 +405,7 @@ export class RuntimeExtensionsEditor extends BaseEditor { multipleSelectionSupport: false, setRowLineHeight: false, horizontalScrolling: false - }) as WorkbenchList; + }); this._list.splice(0, this._list.length, this._elements || undefined); diff --git a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts index 0d310f31f4..70f2c1b6f8 100644 --- a/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts +++ b/src/vs/workbench/contrib/extensions/test/electron-browser/extensionsActions.test.ts @@ -45,6 +45,8 @@ import { IProductService } from 'vs/platform/product/common/product'; import { Schemas } from 'vs/base/common/network'; import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IProgressService } from 'vs/platform/progress/common/progress'; +import { ProgressService } from 'vs/workbench/services/progress/browser/progressService'; suite('ExtensionsActions Test', () => { @@ -69,6 +71,7 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IWorkspaceContextService, new TestContextService()); instantiationService.stub(IConfigurationService, new TestConfigurationService()); + instantiationService.stub(IProgressService, ProgressService); instantiationService.stub(IExtensionGalleryService, ExtensionGalleryService); instantiationService.stub(ISharedProcessService, TestSharedProcessService); @@ -1160,15 +1163,29 @@ suite('ExtensionsActions Test', () => { const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); testObject.extension = extensions[0]; - return new Promise(c => { - testObject.onDidChange(() => { - if (testObject.enabled && testObject.tooltip === 'Please reload Azure Data Studio to complete the uninstallation of this extension.') { // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio - c(); - } - }); - uninstallEvent.fire(local.identifier); - didUninstallEvent.fire({ identifier: local.identifier }); + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); + assert.ok(testObject.enabled); + assert.equal(testObject.tooltip, 'Please reload Azure Data Studio to complete the uninstallation of this extension.'); // {{SQL CARBON EDIT}} - replace Visual Studio Code with Azure Data Studio + }); + + test('Test ReloadAction when extension is uninstalled and can be removed', async () => { + const local = aLocalExtension('a'); + instantiationService.stub(IExtensionService, >{ + getExtensions: () => Promise.resolve([ExtensionsActions.toExtensionDescription(local)]), + onDidChangeExtensions: new Emitter().event, + canRemoveExtension: (extension) => true, + canAddExtension: (extension) => true }); + const testObject: ExtensionsActions.ReloadAction = instantiationService.createInstance(ExtensionsActions.ReloadAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + instantiationService.stubPromise(IExtensionManagementService, 'getInstalled', [local]); + const extensions = await instantiationService.get(IExtensionsWorkbenchService).queryLocal(); + testObject.extension = extensions[0]; + + uninstallEvent.fire(local.identifier); + didUninstallEvent.fire({ identifier: local.identifier }); + assert.ok(!testObject.enabled); }); test('Test ReloadAction when extension is uninstalled and installed', async () => { @@ -1505,9 +1522,11 @@ suite('ExtensionsActions Test', () => { assert.equal('extension-action prominent install', testObject.class); }); - test('Test remote install action when installing local workspace extension', async (done) => { + test('Test remote install action when installing local workspace extension', async () => { // multi server setup const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + remoteExtensionManagementService.onInstallExtension = onInstallExtension.event; const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension]), remoteExtensionManagementService); instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); @@ -1516,7 +1535,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); instantiationService.set(IExtensionsWorkbenchService, workbenchService); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1527,19 +1547,17 @@ suite('ExtensionsActions Test', () => { assert.equal('Install on remote', testObject.label); assert.equal('extension-action prominent install', testObject.class); - remoteExtensionManagementService.installFromGallery = () => new Promise(c => c(aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }))); - const disposable = testObject.onDidChange(() => { - if (testObject.label === 'Installing' && testObject.enabled) { - disposable.dispose(); - done(); - } - }); - testObject.run(); + onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); }); - test('Test remote install action when installing local workspace extension is finished', async (done) => { + test('Test remote install action when installing local workspace extension is finished', async () => { // multi server setup const remoteExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + remoteExtensionManagementService.onInstallExtension = onInstallExtension.event; const onDidInstallEvent = new Emitter(); remoteExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); @@ -1550,7 +1568,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); instantiationService.set(IExtensionsWorkbenchService, workbenchService); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }))); + const gallery = aGalleryExtension('a', { identifier: localWorkspaceExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1561,19 +1580,14 @@ suite('ExtensionsActions Test', () => { assert.equal('Install on remote', testObject.label); assert.equal('extension-action prominent install', testObject.class); - const installedExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); - remoteExtensionManagementService.installFromGallery = () => new Promise(c => c(installedExtension)); - await testObject.run(); + onInstallExtension.fire({ identifier: localWorkspaceExtension.identifier, gallery }); assert.ok(testObject.enabled); - assert.equal('Install on remote', testObject.label); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); - const disposable = testObject.onDidChange(() => { - if (testObject.label === 'Install on remote' && !testObject.enabled) { - disposable.dispose(); - done(); - } - }); + const installedExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install }); + assert.ok(!testObject.enabled); }); test('Test remote install action is enabled for disabled local workspace extension', async () => { @@ -1717,7 +1731,7 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); - test('Test remote install action is disabled for local workspace extension if it cannot be installed', async () => { + test('Test remote install action is enabled for local workspace extension if it has not gallery', async () => { // multi server setup const localWorkspaceExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`) }); const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceExtension])); @@ -1730,6 +1744,25 @@ suite('ExtensionsActions Test', () => { const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test remote install action is disabled for local workspace system extension', async () => { + // multi server setup + const localWorkspaceSystemExtension = aLocalExtension('a', { extensionKind: 'workspace' }, { location: URI.file(`pub.a`), type: ExtensionType.System }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService([localWorkspaceSystemExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: localWorkspaceSystemExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.RemoteInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.localExtensionManagementServer!); testObject.extension = extensions[0]; assert.ok(testObject.extension); @@ -1842,9 +1875,11 @@ suite('ExtensionsActions Test', () => { assert.equal('extension-action prominent install', testObject.class); }); - test('Test local install action when installing remote ui extension', async (done) => { + test('Test local install action when installing remote ui extension', async () => { // multi server setup const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + localExtensionManagementService.onInstallExtension = onInstallExtension.event; const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, localExtensionManagementService, createExtensionManagementService([remoteUIExtension])); instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); @@ -1853,7 +1888,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); instantiationService.set(IExtensionsWorkbenchService, workbenchService); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const gallery = aGalleryExtension('a', { identifier: remoteUIExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1864,19 +1900,17 @@ suite('ExtensionsActions Test', () => { assert.equal('Install Locally', testObject.label); assert.equal('extension-action prominent install', testObject.class); - localExtensionManagementService.installFromGallery = () => new Promise(c => c(aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }))); - const disposable = testObject.onDidChange(() => { - if (testObject.label === 'Installing' && testObject.enabled) { - disposable.dispose(); - done(); - } - }); - testObject.run(); + onInstallExtension.fire({ identifier: remoteUIExtension.identifier, gallery }); + assert.ok(testObject.enabled); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); }); - test('Test local install action when installing remote ui extension is finished', async (done) => { + test('Test local install action when installing remote ui extension is finished', async () => { // multi server setup const localExtensionManagementService: IExtensionManagementService = createExtensionManagementService(); + const onInstallExtension = new Emitter(); + localExtensionManagementService.onInstallExtension = onInstallExtension.event; const onDidInstallEvent = new Emitter(); localExtensionManagementService.onDidInstallExtension = onDidInstallEvent.event; const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); @@ -1887,7 +1921,8 @@ suite('ExtensionsActions Test', () => { instantiationService.stub(IExtensionsWorkbenchService, workbenchService, 'open', undefined); instantiationService.set(IExtensionsWorkbenchService, workbenchService); - instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUIExtension.identifier }))); + const gallery = aGalleryExtension('a', { identifier: remoteUIExtension.identifier }); + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(gallery)); const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); @@ -1898,19 +1933,14 @@ suite('ExtensionsActions Test', () => { assert.equal('Install Locally', testObject.label); assert.equal('extension-action prominent install', testObject.class); - const installedExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); - localExtensionManagementService.installFromGallery = () => new Promise(c => c(installedExtension)); - await testObject.run(); + onInstallExtension.fire({ identifier: remoteUIExtension.identifier, gallery }); assert.ok(testObject.enabled); - assert.equal('Install Locally', testObject.label); + assert.equal('Installing', testObject.label); + assert.equal('extension-action install installing', testObject.class); - const disposable = testObject.onDidChange(() => { - if (testObject.label === 'Install Locally' && !testObject.enabled) { - disposable.dispose(); - done(); - } - }); + const installedExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`) }); onDidInstallEvent.fire({ identifier: installedExtension.identifier, local: installedExtension, operation: InstallOperation.Install }); + assert.ok(!testObject.enabled); }); test('Test local install action is enabled for disabled remote ui extension', async () => { @@ -2057,7 +2087,7 @@ suite('ExtensionsActions Test', () => { assert.ok(!testObject.enabled); }); - test('Test local install action is disabled for remote UI extension if it cannot be installed', async () => { + test('Test local install action is enabled for remote UI extension if it has gallery', async () => { // multi server setup const remoteUIExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }) }); const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUIExtension])); @@ -2070,6 +2100,25 @@ suite('ExtensionsActions Test', () => { const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); instantiationService.createInstance(ExtensionContainers, [testObject]); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); + testObject.extension = extensions[0]; + assert.ok(testObject.extension); + assert.ok(testObject.enabled); + }); + + test('Test local install action is disabled for remote UI system extension', async () => { + // multi server setup + const remoteUISystemExtension = aLocalExtension('a', { extensionKind: 'ui' }, { location: URI.file(`pub.a`).with({ scheme: Schemas.vscodeRemote }), type: ExtensionType.System }); + const extensionManagementServerService = aMultiExtensionManagementServerService(instantiationService, createExtensionManagementService(), createExtensionManagementService([remoteUISystemExtension])); + instantiationService.stub(IExtensionManagementServerService, extensionManagementServerService); + instantiationService.stub(IExtensionEnablementService, new TestExtensionEnablementService(instantiationService)); + const workbenchService: IExtensionsWorkbenchService = instantiationService.createInstance(ExtensionsWorkbenchService); + instantiationService.set(IExtensionsWorkbenchService, workbenchService); + + instantiationService.stubPromise(IExtensionGalleryService, 'query', aPage(aGalleryExtension('a', { identifier: remoteUISystemExtension.identifier }))); + const testObject: ExtensionsActions.InstallAction = instantiationService.createInstance(ExtensionsActions.LocalInstallAction); + instantiationService.createInstance(ExtensionContainers, [testObject]); + const extensions = await workbenchService.queryLocal(extensionManagementServerService.remoteExtensionManagementServer!); testObject.extension = extensions[0]; assert.ok(testObject.extension); diff --git a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts index 6d865bb721..fd1c8d27a8 100644 --- a/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts +++ b/src/vs/workbench/contrib/files/browser/fileActions.contribution.ts @@ -205,7 +205,7 @@ appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, Re appendEditorTitleContextMenuItem(REVEAL_IN_OS_COMMAND_ID, REVEAL_IN_OS_LABEL, ContextKeyExpr.and(IsWebContext.toNegated(), ResourceContextKey.Scheme.isEqualTo(Schemas.userData))); appendEditorTitleContextMenuItem(REVEAL_IN_EXPLORER_COMMAND_ID, nls.localize('revealInSideBar', "Reveal in Side Bar"), ResourceContextKey.IsFileSystemResource); -function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr, group?: string): void { +function appendEditorTitleContextMenuItem(id: string, title: string, when: ContextKeyExpr | undefined, group?: string): void { // Menu MenuRegistry.appendMenuItem(MenuId.EditorTitleContext, { diff --git a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css index 49f3784206..79a575d5e8 100644 --- a/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css +++ b/src/vs/workbench/contrib/files/browser/media/explorerviewlet.css @@ -66,6 +66,8 @@ .explorer-viewlet .panel-header .count { min-width: fit-content; + display: flex; + align-items: center; } .explorer-viewlet .panel-header .monaco-count-badge.hidden { @@ -102,8 +104,9 @@ } .explorer-viewlet .monaco-count-badge { - padding: 1px 6px; + padding: 1px 6px 2px; margin-left: 6px; + min-height: auto; border-radius: 0; /* goes better when ellipsis shows up on narrow sidebar */ } diff --git a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg b/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg index 09c943426e..c109b13c3d 100644 --- a/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg +++ b/src/vs/workbench/contrib/files/browser/media/files-activity-bar.svg @@ -1,3 +1,3 @@ - + diff --git a/src/vs/workbench/contrib/files/browser/views/explorerView.ts b/src/vs/workbench/contrib/files/browser/views/explorerView.ts index a8044c88cc..2e1a7dd678 100644 --- a/src/vs/workbench/contrib/files/browser/views/explorerView.ts +++ b/src/vs/workbench/contrib/files/browser/views/explorerView.ts @@ -302,7 +302,7 @@ export class ExplorerView extends ViewletPanel { sorter: this.instantiationService.createInstance(FileSorter), dnd: this.instantiationService.createInstance(FileDragAndDrop), autoExpandSingleChildren: true - }) as WorkbenchAsyncDataTree; + }); this._register(this.tree); // Bind context keys diff --git a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts index ab5617e1ac..90986b36e2 100644 --- a/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts +++ b/src/vs/workbench/contrib/files/browser/views/openEditorsView.ts @@ -219,7 +219,7 @@ 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); diff --git a/src/vs/workbench/contrib/markers/browser/markersPanel.ts b/src/vs/workbench/contrib/markers/browser/markersPanel.ts index 014bafde22..3702b34c62 100644 --- a/src/vs/workbench/contrib/markers/browser/markersPanel.ts +++ b/src/vs/workbench/contrib/markers/browser/markersPanel.ts @@ -320,7 +320,7 @@ export class MarkersPanel extends Panel implements IMarkerFilterController { dnd: new ResourceDragAndDrop(this.instantiationService), expandOnlyOnTwistieClick: (e: TreeElement) => e instanceof Marker && e.relatedInformation.length > 0 } - ) as any as WorkbenchObjectTree; + ); onDidChangeRenderNodeCount.input = this.tree.onDidChangeRenderNodeCount; diff --git a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts index 46cb24a551..ec1f6b7fe0 100644 --- a/src/vs/workbench/contrib/outline/browser/outlinePanel.ts +++ b/src/vs/workbench/contrib/outline/browser/outlinePanel.ts @@ -319,6 +319,7 @@ export class OutlinePanel extends ViewletPanel { treeContainer, new OutlineVirtualDelegate(), [new OutlineGroupRenderer(), this._treeRenderer], + // https://github.com/microsoft/TypeScript/issues/32526 this._treeDataSource as IDataSource, { expandOnlyOnTwistieClick: true, @@ -328,7 +329,7 @@ export class OutlinePanel extends ViewletPanel { identityProvider: new OutlineIdentityProvider(), keyboardNavigationLabelProvider: new OutlineNavigationLabelProvider() } - ) as WorkbenchDataTree; + ); this._disposables.push(this._tree); this._disposables.push(this._outlineViewState.onDidChange(this._onDidChangeUserState, this)); diff --git a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts index 4f149bd546..0e8f644168 100644 --- a/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/keybindingsEditor.ts @@ -452,13 +452,12 @@ export class KeybindingsEditor extends BaseEditor implements IKeybindingsEditor private createList(parent: HTMLElement): void { this.keybindingsListContainer = DOM.append(parent, $('.keybindings-list-container')); - this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], - { - identityProvider: { getId: (e: IListEntry) => e.id }, - ariaLabel: localize('keybindingsLabel', "Keybindings"), - setRowLineHeight: false, - horizontalScrolling: false - })) as WorkbenchList; + this.keybindingsList = this._register(this.instantiationService.createInstance(WorkbenchList, this.keybindingsListContainer, new Delegate(), [new KeybindingItemRenderer(this, this.instantiationService)], { + identityProvider: { getId: (e: IListEntry) => e.id }, + ariaLabel: localize('keybindingsLabel', "Keybindings"), + setRowLineHeight: false, + horizontalScrolling: false + })); this._register(this.keybindingsList.onContextMenu(e => this.onContextMenu(e))); this._register(this.keybindingsList.onFocusChange(e => this.onFocusChange(e))); this._register(this.keybindingsList.onDidFocus(() => { diff --git a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts index d4c30a25ba..45b5380b96 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferences.contribution.ts @@ -13,7 +13,7 @@ import * as nls from 'vs/nls'; import { MenuId, MenuRegistry, SyncActionDescriptor } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; -import { WorkbenchStateContext, RemoteAuthorityContext, IsMacNativeContext } from 'vs/workbench/browser/contextkeys'; +import { WorkbenchStateContext, IsMacNativeContext, RemoteNameContext } from 'vs/workbench/browser/contextkeys'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation'; @@ -424,7 +424,7 @@ class PreferencesActionsContribution extends Disposable implements IWorkbenchCon title: { value: label, original: `Open Remote Settings (${hostLabel})` }, category: { value: nls.localize('preferencesCategory', "Preferences"), original: 'Preferences' } }, - when: RemoteAuthorityContext.notEqualsTo('') + when: RemoteNameContext.notEqualsTo('') }); }); } diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts index 0e6bc3ce54..cb5c555acd 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesEditor.ts @@ -548,8 +548,11 @@ class PreferencesRenderersController extends Disposable { const targetKey = resource.toString(); if (!this._prefsModelsForSearch.has(targetKey)) { try { - const model = this._register(await this.preferencesService.createPreferencesEditorModel(resource)); - this._prefsModelsForSearch.set(targetKey, model); + const model = await this.preferencesService.createPreferencesEditorModel(resource); + if (model) { + this._register(model); + this._prefsModelsForSearch.set(targetKey, model); + } } catch (e) { // Will throw when the settings file doesn't exist. return undefined; @@ -1116,16 +1119,19 @@ abstract class AbstractSettingsEditorContribution extends Disposable implements private _updatePreferencesRenderer(associatedPreferencesModelUri: URI): Promise | null> { return this.preferencesService.createPreferencesEditorModel(associatedPreferencesModelUri) .then(associatedPreferencesEditorModel => { - return this.preferencesRendererCreationPromise!.then(preferencesRenderer => { - if (preferencesRenderer) { - const associatedPreferencesModel = preferencesRenderer.getAssociatedPreferencesModel(); - if (associatedPreferencesModel) { - associatedPreferencesModel.dispose(); + if (associatedPreferencesEditorModel) { + return this.preferencesRendererCreationPromise!.then(preferencesRenderer => { + if (preferencesRenderer) { + const associatedPreferencesModel = preferencesRenderer.getAssociatedPreferencesModel(); + if (associatedPreferencesModel) { + associatedPreferencesModel.dispose(); + } + preferencesRenderer.setAssociatedPreferencesModel(associatedPreferencesEditorModel); } - preferencesRenderer.setAssociatedPreferencesModel(associatedPreferencesEditorModel); - } - return preferencesRenderer; - }); + return preferencesRenderer; + }); + } + return null; }); } @@ -1193,12 +1199,14 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl } protected _createPreferencesRenderer(): Promise | null> | null { - if (this.isSettingsModel()) { - return this.preferencesService.createPreferencesEditorModel(this.editor.getModel()!.uri) + const model = this.editor.getModel(); + if (model) { + return this.preferencesService.createPreferencesEditorModel(model.uri) .then(settingsModel => { if (settingsModel instanceof SettingsEditorModel && this.editor.getModel()) { switch (settingsModel.configurationTarget) { case ConfigurationTarget.USER_LOCAL: + case ConfigurationTarget.USER_REMOTE: return this.instantiationService.createInstance(UserSettingsRenderer, this.editor, settingsModel); case ConfigurationTarget.WORKSPACE: return this.instantiationService.createInstance(WorkspaceSettingsRenderer, this.editor, settingsModel); @@ -1217,31 +1225,6 @@ class SettingsEditorContribution extends AbstractSettingsEditorContribution impl } return null; } - - private isSettingsModel(): boolean { - const model = this.editor.getModel(); - if (!model) { - return false; - } - - if (this.preferencesService.userSettingsResource && this.preferencesService.userSettingsResource.toString() === model.uri.toString()) { - return true; - } - - if (this.preferencesService.workspaceSettingsResource && this.preferencesService.workspaceSettingsResource.toString() === model.uri.toString()) { - return true; - } - - for (const folder of this.workspaceContextService.getWorkspace().folders) { - const folderSettingsResource = this.preferencesService.getFolderSettingsResource(folder.uri); - if (folderSettingsResource && folderSettingsResource.toString() === model.uri.toString()) { - return true; - } - } - - return false; - } - } registerEditorContribution(SettingsEditorContribution); diff --git a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts index 4d76afe8c5..fb1d94c0cb 100644 --- a/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts +++ b/src/vs/workbench/contrib/preferences/browser/preferencesRenderers.ts @@ -19,7 +19,7 @@ import { IModelDeltaDecoration, TrackedRangeStickiness } from 'vs/editor/common/ import { ModelDecorationOptions } from 'vs/editor/common/model/textModel'; import * as nls from 'vs/nls'; import { ConfigurationTarget, IConfigurationService, overrideIdentifierFromKey } from 'vs/platform/configuration/common/configuration'; -import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, IConfigurationNode } from 'vs/platform/configuration/common/configurationRegistry'; +import { ConfigurationScope, Extensions as ConfigurationExtensions, IConfigurationPropertySchema, IConfigurationRegistry, IConfigurationNode, OVERRIDE_PROPERTY_PATTERN } from 'vs/platform/configuration/common/configurationRegistry'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { Registry } from 'vs/platform/registry/common/platform'; @@ -960,9 +960,15 @@ class UnsupportedSettingsRenderer extends Disposable { private settingsEditorModel: SettingsEditorModel, @IMarkerService private markerService: IMarkerService, @IWorkbenchEnvironmentService private workbenchEnvironmentService: IWorkbenchEnvironmentService, + @IConfigurationService private configurationService: IConfigurationService, ) { super(); - this._register(this.editor.getModel()!.onDidChangeContent(() => this.renderingDelayer.trigger(() => this.render()))); + this._register(this.editor.getModel()!.onDidChangeContent(() => this.delayedRender())); + this._register(Event.filter(this.configurationService.onDidChangeConfiguration, e => e.source === ConfigurationTarget.DEFAULT)(() => this.delayedRender())); + } + + private delayedRender(): void { + this.renderingDelayer.trigger(() => this.render()); } public render(): void { @@ -996,14 +1002,11 @@ class UnsupportedSettingsRenderer extends Disposable { this.handleWorkspaceFolderConfiguration(setting, configuration, markerData); break; } - } else { + } else if (!OVERRIDE_PROPERTY_PATTERN.test(setting.key)) { // Ignore override settings (language specific settings) markerData.push({ severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.valueRange.endLineNumber, - endColumn: setting.valueRange.endColumn, + ...setting.range, message: nls.localize('unknown configuration setting', "Unknown Configuration Setting") }); } @@ -1018,10 +1021,7 @@ class UnsupportedSettingsRenderer extends Disposable { markerData.push({ severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.valueRange.endLineNumber, - endColumn: setting.valueRange.endColumn, + ...setting.range, message: nls.localize('unsupportedRemoteMachineSetting', "This setting can be applied only in remote machine settings") }); } @@ -1056,10 +1056,7 @@ class UnsupportedSettingsRenderer extends Disposable { markerData.push({ severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.valueRange.endLineNumber, - endColumn: setting.valueRange.endColumn, + ...setting.range, message: nls.localize('unsupportedWindowSetting', "This setting cannot be applied now. It will be applied when you open this folder directly.") }); } @@ -1069,10 +1066,7 @@ class UnsupportedSettingsRenderer extends Disposable { return { severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.keyRange.endLineNumber, - endColumn: setting.keyRange.endColumn, + ...setting.range, message: nls.localize('unsupportedApplicationSetting', "This setting can be applied only in application user settings") }; } @@ -1081,10 +1075,7 @@ class UnsupportedSettingsRenderer extends Disposable { return { severity: MarkerSeverity.Hint, tags: [MarkerTag.Unnecessary], - startLineNumber: setting.keyRange.startLineNumber, - startColumn: setting.keyRange.startColumn, - endLineNumber: setting.valueRange.endLineNumber, - endColumn: setting.valueRange.endColumn, + ...setting.range, message: nls.localize('unsupportedMachineSetting', "This setting can be applied only in user settings") }; } 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 7554ecdd8a..c8cb11959e 100644 --- a/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts +++ b/src/vs/workbench/contrib/remote/electron-browser/remote.contribution.ts @@ -37,7 +37,7 @@ import Severity from 'vs/base/common/severity'; import { ReloadWindowAction } from 'vs/workbench/browser/actions/windowActions'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { IWindowsService } from 'vs/platform/windows/common/windows'; -import { RemoteConnectionState } from 'vs/workbench/browser/contextkeys'; +import { RemoteConnectionState, Deprecated_RemoteAuthorityContext } from 'vs/workbench/browser/contextkeys'; import { IDownloadService } from 'vs/platform/download/common/download'; const WINDOW_ACTIONS_COMMAND_ID = 'remote.showActions'; @@ -49,7 +49,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc private windowCommandMenu: IMenu; private hasWindowActions: boolean = false; private remoteAuthority: string | undefined; - private disconnected: boolean = true; + private connectionState: 'initializing' | 'connected' | 'disconnected' | undefined = undefined; constructor( @IStatusbarService private readonly statusbarService: IStatusbarService, @@ -76,7 +76,8 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc if (this.remoteAuthority) { // Pending entry until extensions are ready this.renderWindowIndicator(nls.localize('host.open', "$(sync~spin) Opening Remote..."), undefined, WINDOW_ACTIONS_COMMAND_ID); - RemoteConnectionState.bindTo(this.contextKeyService).set('initializing'); + this.connectionState = 'initializing'; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); MenuRegistry.appendMenuItem(MenuId.MenubarFileMenu, { group: '6_close', @@ -86,6 +87,23 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc }, order: 3.5 }); + + const connection = remoteAgentService.getConnection(); + if (connection) { + this._register(connection.onDidStateChange((e) => { + switch (e.type) { + case PersistentConnectionEventType.ConnectionLost: + case PersistentConnectionEventType.ReconnectionPermanentFailure: + case PersistentConnectionEventType.ReconnectionRunning: + case PersistentConnectionEventType.ReconnectionWait: + this.setDisconnected(true); + break; + case PersistentConnectionEventType.ConnectionGain: + this.setDisconnected(false); + break; + } + })); + } } extensionService.whenInstalledExtensionsRegistered().then(_ => { @@ -96,29 +114,14 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc this._register(this.windowCommandMenu.onDidChange(e => this.updateWindowActions())); this.updateWindowIndicator(); }); - - const connection = remoteAgentService.getConnection(); - if (connection) { - this._register(connection.onDidStateChange((e) => { - switch (e.type) { - case PersistentConnectionEventType.ConnectionLost: - case PersistentConnectionEventType.ReconnectionPermanentFailure: - case PersistentConnectionEventType.ReconnectionRunning: - case PersistentConnectionEventType.ReconnectionWait: - this.setDisconnected(true); - break; - case PersistentConnectionEventType.ConnectionGain: - this.setDisconnected(false); - break; - } - })); - } } private setDisconnected(isDisconnected: boolean): void { - if (this.disconnected !== isDisconnected) { - this.disconnected = isDisconnected; - RemoteConnectionState.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected' : 'connected'); + const newState = isDisconnected ? 'disconnected' : 'connected'; + if (this.connectionState !== newState) { + this.connectionState = newState; + RemoteConnectionState.bindTo(this.contextKeyService).set(this.connectionState); + Deprecated_RemoteAuthorityContext.bindTo(this.contextKeyService).set(isDisconnected ? 'disconnected/${this.remoteAuthority!}' : this.remoteAuthority!); this.updateWindowIndicator(); } } @@ -127,7 +130,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc const windowActionCommand = (this.remoteAuthority || this.windowCommandMenu.getActions().length) ? WINDOW_ACTIONS_COMMAND_ID : undefined; if (this.remoteAuthority) { const hostLabel = this.labelService.getHostLabel(REMOTE_HOST_SCHEME, this.remoteAuthority) || this.remoteAuthority; - if (!this.disconnected) { + if (this.connectionState !== 'disconnected') { this.renderWindowIndicator(`$(remote) ${hostLabel}`, nls.localize('host.tooltip', "Editing on {0}", hostLabel), windowActionCommand); } else { this.renderWindowIndicator(`$(alert) ${nls.localize('disconnectedFrom', "Disconnected from")} ${hostLabel}`, nls.localize('host.tooltipDisconnected', "Disconnected from {0}", hostLabel), windowActionCommand); @@ -163,7 +166,7 @@ export class RemoteWindowActiveIndicator extends Disposable implements IWorkbenc private showIndicatorActions(menu: IMenu) { - const actions = !this.disconnected || !this.remoteAuthority ? menu.getActions() : []; + const actions = menu.getActions(); const items: (IQuickPickItem | IQuickPickSeparator)[] = []; for (let actionGroup of actions) { @@ -467,4 +470,4 @@ Registry.as(ConfigurationExtensions.Configuration) } } } - }); \ No newline at end of file + }); diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts index 1a8cc25339..f1b1abe8e1 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorker.ts @@ -3,7 +3,7 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI, UriComponents } from 'vs/base/common/uri'; +import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { getMediaMime } from 'vs/base/common/mime'; @@ -71,7 +71,8 @@ async function respondWithDefault(event: FetchEvent): Promise { } async function respondWithResource(event: FetchEvent, uri: URI): Promise { - const cachedValue = await caches.open(_cacheName).then(cache => cache.match(event.request)); + const cacheKey = event.request.url.replace('&r=1', ''); + const cachedValue = await caches.open(_cacheName).then(cache => cache.match(cacheKey)); if (cachedValue) { return cachedValue; } @@ -79,26 +80,27 @@ async function respondWithResource(event: FetchEvent, uri: URI): Promise(resolve => { const token = generateUuid(); - const query: { u: UriComponents, i: number } = JSON.parse(uri.query); + const [first] = uri.query.split('&'); + const components = JSON.parse(first.substr(2)); _pendingFetch.set(token, async (data: ArrayBuffer, isExtensionResource: boolean) => { const res = new Response(data, { status: 200, - headers: { 'Content-Type': getMediaMime(query.u.path) || 'text/plain' } + headers: { 'Content-Type': getMediaMime(components.path) || 'text/plain' } }); if (isExtensionResource) { // only cache extension resources but not other // resources, esp not workspace resources - await caches.open(_cacheName).then(cache => cache.put(event.request, res.clone())); + await caches.open(_cacheName).then(cache => cache.put(cacheKey, res.clone())); } return resolve(res); }); self.clients.get(event.clientId).then(client => { - client.postMessage({ uri: query.u, token }); + client.postMessage({ uri: components, token }); }); }); } diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts index b5207aadf0..19220cb30a 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerClient.ts @@ -65,11 +65,12 @@ class ResourceServiceWorker { @IExtensionService private readonly _extensionService: IExtensionService, @ILogService private readonly _logService: ILogService, ) { + this._updateEarlyResourceUris(); _serviceWorker.claim(e => this._handleMessage(e)); } private _handleMessage(event: ExtendableMessageEvent): void { - this._logService.trace('SW#fetch', event.data.uri); + this._logService.trace('SW - fetch', event.data.uri); const uri = URI.revive(event.data.uri); Promise.all([ @@ -95,6 +96,53 @@ class ResourceServiceWorker { } return false; } + + private _updateEarlyResourceUris(): void { + + let updateCount = 0; + + // find style-tags + const styleElements = document.querySelectorAll('style'); + for (let i = 0; i < styleElements.length; i++) { + const el = styleElements.item(i); + if (!el.sheet) { + continue; + } + const rules = (el.sheet).rules; + for (let j = 0; j < rules.length; j++) { + const rule = rules[j]; + const newCssText = this._updateResourceUris(rule.cssText); + if (newCssText) { + (el.sheet).deleteRule(j); + (el.sheet).insertRule(newCssText, j); + updateCount += 1; + } + } + } + + // find any tag using remote uris + const htmlElements = document.querySelectorAll('[style*="/vscode-resources/fetch"]'); + for (let i = 0; i < htmlElements.length; i++) { + const el = htmlElements.item(i); + const newCssText = this._updateResourceUris(el.style.cssText); + if (newCssText) { + el.style.cssText = newCssText; + updateCount += 1; + } + } + + this._logService.trace('SW - count of changed, early dom element: ', updateCount); + } + + private _updateResourceUris(cssText: string): string | undefined { + let changed = false; + let newCssText = cssText.replace(/url\((["'])?(.+?\/vscode-resources\/fetch\?.+?)\1\)/g, (_match, g1, g2, _offset, _input) => { + changed = true; + return `url(${g1 || ''}${g2}&r=1${g1 || ''})`; + }); + + return changed ? newCssText : undefined; + } } Registry.as(Extensions.Workbench).registerWorkbenchContribution( diff --git a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts index b67d08da44..87eaf7829c 100644 --- a/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts +++ b/src/vs/workbench/contrib/resources/browser/resourceServiceWorkerMain.ts @@ -10,7 +10,7 @@ // statement. // trigger service worker updates -const _tag = '66399613-d758-4b88-b073-ff4195611d70'; +const _tag = 'a6f9835e-c10e-4299-ab39-b8e29547c20a'; // loader world const baseUrl = '../../../../../'; diff --git a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg b/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg index 9aa985bc97..5092b85732 100644 --- a/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg +++ b/src/vs/workbench/contrib/scm/browser/media/scm-activity-bar.svg @@ -1,3 +1,10 @@ - - + + + + + + + + + diff --git a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts index c9d71512a3..fb64a95fa0 100644 --- a/src/vs/workbench/contrib/scm/browser/scm.contribution.ts +++ b/src/vs/workbench/contrib/scm/browser/scm.contribution.ts @@ -18,7 +18,7 @@ import { SCMViewlet } from 'vs/workbench/contrib/scm/browser/scmViewlet'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; import { IConfigurationRegistry, Extensions as ConfigurationExtensions } from 'vs/platform/configuration/common/configurationRegistry'; import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; -import { ContextKeyDefinedExpr, IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IContextKeyService, ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { KeybindingsRegistry, KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; @@ -117,7 +117,7 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({ id: 'scm.acceptInput', description: { description: localize('scm accept', "SCM: Accept Input"), args: [] }, weight: KeybindingWeight.WorkbenchContrib, - when: new ContextKeyDefinedExpr('scmRepository'), + when: ContextKeyExpr.has('scmRepository'), primary: KeyMod.CtrlCmd | KeyCode.Enter, handler: accessor => { const contextKeyService = accessor.get(IContextKeyService); diff --git a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts index 6706863fc6..23904992c1 100644 --- a/src/vs/workbench/contrib/scm/browser/scmViewlet.ts +++ b/src/vs/workbench/contrib/scm/browser/scmViewlet.ts @@ -245,7 +245,7 @@ export class MainPanel extends ViewletPanel { this.list = this.instantiationService.createInstance(WorkbenchList, container, delegate, [renderer], { identityProvider, horizontalScrolling: false - }) as WorkbenchList; + }); this._register(renderer.onDidRenderElement(e => this.list.updateWidth(this.viewModel.repositories.indexOf(e)), null)); this._register(this.list.onSelectionChange(this.onListSelectionChange, this)); @@ -850,7 +850,7 @@ export class RepositoryPanel extends ViewletPanel { identityProvider: scmResourceIdentityProvider, keyboardNavigationLabelProvider: scmKeyboardNavigationLabelProvider, horizontalScrolling: false - }) as WorkbenchList; + }); this._register(Event.chain(this.list.onDidOpen) .map(e => e.elements[0]) diff --git a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg b/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg index b40063bef3..a7ea9ab29a 100644 --- a/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg +++ b/src/vs/workbench/contrib/search/browser/media/search-activity-bar.svg @@ -1,3 +1,3 @@ - + diff --git a/src/vs/workbench/contrib/search/browser/replaceService.ts b/src/vs/workbench/contrib/search/browser/replaceService.ts index 67d46e4ffa..5488254d36 100644 --- a/src/vs/workbench/contrib/search/browser/replaceService.ts +++ b/src/vs/workbench/contrib/search/browser/replaceService.ts @@ -67,7 +67,7 @@ class ReplacePreviewModel extends Disposable { resolve(replacePreviewUri: URI): Promise { const fileResource = toFileResource(replacePreviewUri); - const fileMatch = this.searchWorkbenchService.searchModel.searchResult.matches().filter(match => match.resource().toString() === fileResource.toString())[0]; + const fileMatch = this.searchWorkbenchService.searchModel.searchResult.matches().filter(match => match.resource.toString() === fileResource.toString())[0]; return this.textModelResolverService.createModelReference(fileResource).then(ref => { ref = this._register(ref); const sourceModel = ref.object.textEditorModel; @@ -112,8 +112,8 @@ export class ReplaceService implements IReplaceService { const fileMatch = element instanceof Match ? element.parent() : element; return this.editorService.openEditor({ - leftResource: fileMatch.resource(), - rightResource: toReplaceResource(fileMatch.resource()), + leftResource: fileMatch.resource, + rightResource: toReplaceResource(fileMatch.resource), label: nls.localize('fileReplaceChanges', "{0} ↔ {1} (Replace Preview)", fileMatch.name(), fileMatch.name()), options: { preserveFocus, @@ -139,8 +139,8 @@ export class ReplaceService implements IReplaceService { } updateReplacePreview(fileMatch: FileMatch, override: boolean = false): Promise { - const replacePreviewUri = toReplaceResource(fileMatch.resource()); - return Promise.all([this.textModelResolverService.createModelReference(fileMatch.resource()), this.textModelResolverService.createModelReference(replacePreviewUri)]) + const replacePreviewUri = toReplaceResource(fileMatch.resource); + return Promise.all([this.textModelResolverService.createModelReference(fileMatch.resource), this.textModelResolverService.createModelReference(replacePreviewUri)]) .then(([sourceModelRef, replaceModelRef]) => { const sourceModel = sourceModelRef.object.textEditorModel; const replaceModel = replaceModelRef.object.textEditorModel; @@ -200,7 +200,7 @@ export class ReplaceService implements IReplaceService { private createEdit(match: Match, text: string, resource: URI | null = null): ResourceTextEdit { const fileMatch: FileMatch = match.parent(); const resourceEdit: ResourceTextEdit = { - resource: resource !== null ? resource : fileMatch.resource(), + resource: resource !== null ? resource : fileMatch.resource, edits: [{ range: match.range(), text: text diff --git a/src/vs/workbench/contrib/search/browser/search.contribution.ts b/src/vs/workbench/contrib/search/browser/search.contribution.ts index d4efb61958..3e2eb640d3 100644 --- a/src/vs/workbench/contrib/search/browser/search.contribution.ts +++ b/src/vs/workbench/contrib/search/browser/search.contribution.ts @@ -219,7 +219,7 @@ CommandsRegistry.registerCommand({ const viewletService = accessor.get(IViewletService); const explorerService = accessor.get(IExplorerService); const contextService = accessor.get(IWorkspaceContextService); - const uri = fileMatch.resource(); + const uri = fileMatch.resource; viewletService.openViewlet(VIEWLET_ID_FILES, false).then((viewlet: ExplorerViewlet) => { if (uri && contextService.isInsideWorkspace(uri)) { diff --git a/src/vs/workbench/contrib/search/browser/searchActions.ts b/src/vs/workbench/contrib/search/browser/searchActions.ts index c0887ff9f4..61ad9222fb 100644 --- a/src/vs/workbench/contrib/search/browser/searchActions.ts +++ b/src/vs/workbench/contrib/search/browser/searchActions.ts @@ -654,14 +654,14 @@ export class ReplaceAction extends AbstractSearchAndReplaceAction { } private hasSameParent(element: RenderableMatch): boolean { - return element && element instanceof Match && element.parent().resource() === this.element.parent().resource(); + return element && element instanceof Match && element.parent().resource === this.element.parent().resource; } private hasToOpenFile(): boolean { const activeEditor = this.editorService.activeEditor; const file = activeEditor ? activeEditor.getResource() : undefined; if (file) { - return file.toString() === this.element.parent().resource().toString(); + return file.toString() === this.element.parent().resource.toString(); } return false; } @@ -674,7 +674,7 @@ function uriToClipboardString(resource: URI): string { export const copyPathCommand: ICommandHandler = async (accessor, fileMatch: FileMatch | FolderMatch) => { const clipboardService = accessor.get(IClipboardService); - const text = uriToClipboardString(fileMatch.resource()); + const text = uriToClipboardString(fileMatch.resource); await clipboardService.writeText(text); }; @@ -712,7 +712,7 @@ function fileMatchToString(fileMatch: FileMatch, maxMatches: number): { text: st .slice(0, maxMatches) .map(match => matchToString(match, 2)); return { - text: `${uriToClipboardString(fileMatch.resource())}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`, + text: `${uriToClipboardString(fileMatch.resource)}${lineDelimiter}${matchTextRows.join(lineDelimiter)}`, count: matchTextRows.length }; } diff --git a/src/vs/workbench/contrib/search/browser/searchResultsView.ts b/src/vs/workbench/contrib/search/browser/searchResultsView.ts index cd632e731e..08b50b6643 100644 --- a/src/vs/workbench/contrib/search/browser/searchResultsView.ts +++ b/src/vs/workbench/contrib/search/browser/searchResultsView.ts @@ -115,11 +115,11 @@ export class FolderMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IFolderMatchTemplate): void { const folderMatch = node.element; if (folderMatch.hasResource()) { - const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource()); - if (workspaceFolder && resources.isEqual(workspaceFolder.uri, folderMatch.resource())) { - templateData.label.setFile(folderMatch.resource(), { fileKind: FileKind.ROOT_FOLDER, hidePath: true }); + const workspaceFolder = this.contextService.getWorkspaceFolder(folderMatch.resource); + if (workspaceFolder && resources.isEqual(workspaceFolder.uri, folderMatch.resource)) { + templateData.label.setFile(folderMatch.resource, { fileKind: FileKind.ROOT_FOLDER, hidePath: true }); } else { - templateData.label.setFile(folderMatch.resource(), { fileKind: FileKind.FOLDER }); + templateData.label.setFile(folderMatch.resource, { fileKind: FileKind.FOLDER }); } } else { templateData.label.setLabel(nls.localize('searchFolderMatch.other.label', "Other files")); @@ -185,8 +185,8 @@ export class FileMatchRenderer extends Disposable implements ITreeRenderer, index: number, templateData: IFileMatchTemplate): void { const fileMatch = node.element; - templateData.el.setAttribute('data-resource', fileMatch.resource().toString()); - templateData.label.setFile(fileMatch.resource(), { hideIcon: false }); + templateData.el.setAttribute('data-resource', fileMatch.resource.toString()); + templateData.label.setFile(fileMatch.resource, { hideIcon: false }); const count = fileMatch.count(); templateData.badge.setCount(count); templateData.badge.setTitleFormat(count > 1 ? nls.localize('searchMatches', "{0} matches found", count) : nls.localize('searchMatch', "{0} match found", count)); @@ -316,7 +316,7 @@ export class SearchAccessibilityProvider implements IAccessibilityProvider { const element = elements[0]; return element instanceof FileMatch ? - resources.basename(element.resource()) : + resources.basename(element.resource) : undefined; } @@ -370,7 +370,7 @@ export class SearchDND implements ITreeDragAndDrop { const elements = (data as ElementsDragAndDropData).elements; const resources: URI[] = elements .filter(e => e instanceof FileMatch) - .map((fm: FileMatch) => fm.resource()); + .map((fm: FileMatch) => fm.resource); if (resources.length) { // Apply some datatransfer types to allow for dragging the element outside of the application diff --git a/src/vs/workbench/contrib/search/browser/searchView.ts b/src/vs/workbench/contrib/search/browser/searchView.ts index 122594b1fd..7e3bfcbd78 100644 --- a/src/vs/workbench/contrib/search/browser/searchView.ts +++ b/src/vs/workbench/contrib/search/browser/searchView.ts @@ -633,7 +633,7 @@ export class SearchView extends ViewletPanel { }; this.treeLabels = this._register(this.instantiationService.createInstance(ResourceLabels, { onDidChangeVisibility: this.onDidChangeBodyVisibility })); - this.tree = this._register(>this.instantiationService.createInstance(WorkbenchObjectTree, + this.tree = this._register(this.instantiationService.createInstance(WorkbenchObjectTree, this.resultsElement, delegate, [ @@ -896,13 +896,13 @@ export class SearchView extends ViewletPanel { 0 : dom.getTotalHeight(this.messagesElement); - const searchResultContainerSize = this.size.height - + const searchResultContainerHeight = this.size.height - messagesSize - dom.getTotalHeight(this.searchWidgetsContainerElement); - this.resultsElement.style.height = searchResultContainerSize + 'px'; + this.resultsElement.style.height = searchResultContainerHeight + 'px'; - this.tree.layout(searchResultContainerSize, this.size.width); + this.tree.layout(searchResultContainerHeight, this.size.width); } protected layoutBody(height: number, width: number): void { @@ -1542,7 +1542,7 @@ export class SearchView extends ViewletPanel { open(element: FileMatchOrMatch, preserveFocus?: boolean, sideBySide?: boolean, pinned?: boolean): Promise { const selection = this.getSelectionFrom(element); - const resource = element instanceof Match ? element.parent().resource() : (element).resource(); + const resource = element instanceof Match ? element.parent().resource : (element).resource; return this.editorService.openEditor({ resource: resource, options: { @@ -1600,7 +1600,7 @@ export class SearchView extends ViewletPanel { if (!this.untitledEditorService.isDirty(resource)) { const matches = this.viewModel.searchResult.matches(); for (let i = 0, len = matches.length; i < len; i++) { - if (resource.toString() === matches[i].resource().toString()) { + if (resource.toString() === matches[i].resource.toString()) { this.viewModel.searchResult.remove(matches[i]); } } @@ -1614,11 +1614,8 @@ export class SearchView extends ViewletPanel { const matches = this.viewModel.searchResult.matches(); - for (let i = 0, len = matches.length; i < len; i++) { - if (e.contains(matches[i].resource(), FileChangeType.DELETED)) { - this.viewModel.searchResult.remove(matches[i]); - } - } + const changedMatches = matches.filter(m => e.contains(m.resource, FileChangeType.DELETED)); + this.viewModel.searchResult.remove(changedMatches); } getActions(): IAction[] { diff --git a/src/vs/workbench/contrib/search/common/searchModel.ts b/src/vs/workbench/contrib/search/common/searchModel.ts index 945c56f5df..8f1534330e 100644 --- a/src/vs/workbench/contrib/search/common/searchModel.ts +++ b/src/vs/workbench/contrib/search/common/searchModel.ts @@ -146,7 +146,7 @@ export class Match { } } -export class FileMatch extends Disposable { +export class FileMatch extends Disposable implements IFileMatch { private static readonly _CURRENT_FIND_MATCH = ModelDecorationOptions.register({ stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, @@ -309,7 +309,7 @@ export class FileMatch extends Disposable { } id(): string { - return this.resource().toString(); + return this.resource.toString(); } parent(): BaseFolderMatch { @@ -357,12 +357,12 @@ export class FileMatch extends Disposable { return this.matches().length; } - resource(): URI { + get resource(): URI { return this._resource; } name(): string { - return getBaseLabel(this.resource()); + return getBaseLabel(this.resource); } add(match: Match, trigger?: boolean) { @@ -432,7 +432,7 @@ export class BaseFolderMatch extends Disposable { return this._id; } - resource(): URI | null { + get resource(): URI | null { return this._resource; } @@ -441,7 +441,7 @@ export class BaseFolderMatch extends Disposable { } name(): string { - return getBaseLabel(withNullAsUndefined(this.resource())) || ''; + return getBaseLabel(withNullAsUndefined(this.resource)) || ''; } parent(): SearchResult { @@ -494,8 +494,8 @@ export class BaseFolderMatch extends Disposable { this._onChange.fire({ elements: changed, removed: true }); } - remove(match: FileMatch): void { - this.doRemove(match); + remove(matches: FileMatch | FileMatch[]): void { + this.doRemove(matches); } replace(match: FileMatch): Promise { @@ -530,7 +530,7 @@ export class BaseFolderMatch extends Disposable { private onFileChange(fileMatch: FileMatch): void { let added: boolean = false; let removed: boolean = false; - if (!this._fileMatches.has(fileMatch.resource())) { + if (!this._fileMatches.has(fileMatch.resource)) { this.doAdd(fileMatch); added = true; } @@ -545,22 +545,28 @@ export class BaseFolderMatch extends Disposable { } private doAdd(fileMatch: FileMatch): void { - this._fileMatches.set(fileMatch.resource(), fileMatch); - if (this._unDisposedFileMatches.has(fileMatch.resource())) { - this._unDisposedFileMatches.delete(fileMatch.resource()); + this._fileMatches.set(fileMatch.resource, fileMatch); + if (this._unDisposedFileMatches.has(fileMatch.resource)) { + this._unDisposedFileMatches.delete(fileMatch.resource); } } - private doRemove(fileMatch: FileMatch, dispose: boolean = true, trigger: boolean = true): void { - this._fileMatches.delete(fileMatch.resource()); - if (dispose) { - fileMatch.dispose(); - } else { - this._unDisposedFileMatches.set(fileMatch.resource(), fileMatch); + private doRemove(fileMatches: FileMatch | FileMatch[], dispose: boolean = true, trigger: boolean = true): void { + if (!Array.isArray(fileMatches)) { + fileMatches = [fileMatches]; + } + + for (let match of fileMatches) { + this._fileMatches.delete(match.resource); + if (dispose) { + match.dispose(); + } else { + this._unDisposedFileMatches.set(match.resource, match); + } } if (trigger) { - this._onChange.fire({ elements: [fileMatch], removed: true }); + this._onChange.fire({ elements: fileMatches, removed: true }); } } @@ -590,7 +596,7 @@ export class FolderMatch extends BaseFolderMatch { super(_resource, _id, _index, _query, _parent, _searchModel, replaceService, instantiationService); } - resource(): URI { + get resource(): URI { return this._resource!; } } @@ -605,7 +611,7 @@ export function searchMatchComparer(elementA: RenderableMatch, elementB: Rendera } if (elementA instanceof FileMatch && elementB instanceof FileMatch) { - return elementA.resource().fsPath.localeCompare(elementB.resource().fsPath) || elementA.name().localeCompare(elementB.name()); + return elementA.resource.fsPath.localeCompare(elementB.resource.fsPath) || elementA.name().localeCompare(elementB.name()); } if (elementA instanceof Match && elementB instanceof Match) { @@ -652,7 +658,7 @@ export class SearchResult extends Disposable { .map(fq => fq.folder) .map((resource, index) => this.createFolderMatch(resource, resource.toString(), index, query)); - this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource().toString(), fm)); + this._folderMatches.forEach(fm => this._folderMatchesMap.set(fm.resource.toString(), fm)); this._otherFilesMatch = this.createOtherFilesFolderMatch('otherFiles', this._folderMatches.length + 1, query); this._query = query; @@ -686,26 +692,9 @@ export class SearchResult extends Disposable { add(allRaw: IFileMatch[], silent: boolean = false): void { // Split up raw into a list per folder so we can do a batch add per folder. - const rawPerFolder = new ResourceMap(); - const otherFileMatches: IFileMatch[] = []; - this._folderMatches.forEach(fm => rawPerFolder.set(fm.resource(), [])); - allRaw.forEach(rawFileMatch => { - const folderMatch = this.getFolderMatch(rawFileMatch.resource); - if (!folderMatch) { - // foldermatch was previously removed by user or disposed for some reason - return; - } - - const resource = folderMatch.resource(); - if (resource) { - rawPerFolder.get(resource)!.push(rawFileMatch); - } else { - otherFileMatches.push(rawFileMatch); - } - }); - - rawPerFolder.forEach((raw) => { + const { byFolder, other } = this.groupFilesByFolder(allRaw); + byFolder.forEach(raw => { if (!raw.length) { return; } @@ -716,7 +705,7 @@ export class SearchResult extends Disposable { } }); - this._otherFilesMatch!.add(otherFileMatches, silent); + this._otherFilesMatch!.add(other, silent); } clear(): void { @@ -724,16 +713,31 @@ export class SearchResult extends Disposable { this.disposeMatches(); } - remove(match: FileMatch | FolderMatch): void { - if (match instanceof FileMatch) { - this.getFolderMatch(match.resource()).remove(match); - } else { - match.clear(); + remove(matches: FileMatch | FileMatch[]): void { + if (!Array.isArray(matches)) { + matches = [matches]; + } + + const { byFolder, other } = this.groupFilesByFolder(matches); + byFolder.forEach(matches => { + if (!matches.length) { + return; + } + + this.getFolderMatch(matches[0].resource).remove(matches); + }); + + if (other.length) { + this.getFolderMatch(other[0].resource).remove(other); } } + removeFolder(match: FolderMatch): void { + match.clear(); + } + replace(match: FileMatch): Promise { - return this.getFolderMatch(match.resource()).replace(match); + return this.getFolderMatch(match.resource).replace(match); } replaceAll(progress: IProgress): Promise { @@ -807,7 +811,7 @@ export class SearchResult extends Disposable { if (this._showHighlights && selectedMatch) { // TS? this._rangeHighlightDecorations.highlightRange( - (selectedMatch).parent().resource(), + (selectedMatch).parent().resource, (selectedMatch).range() ); } else { @@ -830,6 +834,32 @@ export class SearchResult extends Disposable { }); } + private groupFilesByFolder(fileMatches: IFileMatch[]): { byFolder: ResourceMap, other: IFileMatch[] } { + const rawPerFolder = new ResourceMap(); + const otherFileMatches: IFileMatch[] = []; + this._folderMatches.forEach(fm => rawPerFolder.set(fm.resource, [])); + + fileMatches.forEach(rawFileMatch => { + const folderMatch = this.getFolderMatch(rawFileMatch.resource); + if (!folderMatch) { + // foldermatch was previously removed by user or disposed for some reason + return; + } + + const resource = folderMatch.resource; + if (resource) { + rawPerFolder.get(resource)!.push(rawFileMatch); + } else { + otherFileMatches.push(rawFileMatch); + } + }); + + return { + byFolder: rawPerFolder, + other: otherFileMatches + }; + } + private disposeMatches(): void { this.folderMatches().forEach(folderMatch => folderMatch.dispose()); this._folderMatches = []; diff --git a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts index ef7eeb7a85..6e55f8eb1a 100644 --- a/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts +++ b/src/vs/workbench/contrib/search/test/browser/searchActions.test.ts @@ -155,4 +155,4 @@ suite('Search Actions', () => { instantiationService.stub(IConfigurationService, new TestConfigurationService()); return instantiationService.createInstance(ModelServiceImpl); } -}); \ No newline at end of file +}); diff --git a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts index b021e53b3f..3309207177 100644 --- a/src/vs/workbench/contrib/search/test/common/searchModel.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchModel.test.ts @@ -130,7 +130,7 @@ suite('SearchModel', () => { const actual = testObject.searchResult.matches(); assert.equal(2, actual.length); - assert.equal('file://c:/1', actual[0].resource().toString()); + assert.equal('file://c:/1', actual[0].resource.toString()); let actuaMatches = actual[0].matches(); assert.equal(2, actuaMatches.length); diff --git a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts index 9984d40836..754d3f6399 100644 --- a/src/vs/workbench/contrib/search/test/common/searchResult.test.ts +++ b/src/vs/workbench/contrib/search/test/common/searchResult.test.ts @@ -55,12 +55,12 @@ suite('SearchResult', () => { test('File Match', function () { let fileMatch = aFileMatch('folder/file.txt'); assert.equal(fileMatch.matches(), 0); - assert.equal(fileMatch.resource().toString(), 'file:///folder/file.txt'); + assert.equal(fileMatch.resource.toString(), 'file:///folder/file.txt'); assert.equal(fileMatch.name(), 'file.txt'); fileMatch = aFileMatch('file.txt'); assert.equal(fileMatch.matches(), 0); - assert.equal(fileMatch.resource().toString(), 'file:///file.txt'); + assert.equal(fileMatch.resource.toString(), 'file:///file.txt'); assert.equal(fileMatch.name(), 'file.txt'); }); @@ -156,7 +156,7 @@ suite('SearchResult', () => { const actual = testObject.matches(); assert.equal(1, actual.length); - assert.equal('file://c:/', actual[0].resource().toString()); + assert.equal('file://c:/', actual[0].resource.toString()); const actuaMatches = actual[0].matches(); assert.equal(3, actuaMatches.length); @@ -186,7 +186,7 @@ suite('SearchResult', () => { const actual = testObject.matches(); assert.equal(2, actual.length); - assert.equal('file://c:/1', actual[0].resource().toString()); + assert.equal('file://c:/1', actual[0].resource.toString()); let actuaMatches = actual[0].matches(); assert.equal(2, actuaMatches.length); @@ -228,13 +228,30 @@ suite('SearchResult', () => { testObject.add([ aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; testObject.onChange(target); - testObject.remove(objectRoRemove); + testObject.remove(objectToRemove); assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); + }); + + test('remove array triggers change event', function () { + const target = sinon.spy(); + const testObject = aSearchResult(); + testObject.add([ + aRawMatch('file://c:/1', + new TextSearchMatch('preview 1', lineOneRange)), + aRawMatch('file://c:/2', + new TextSearchMatch('preview 2', lineOneRange))]); + const arrayToRemove = testObject.matches(); + testObject.onChange(target); + + testObject.remove(arrayToRemove); + + assert.ok(target.calledOnce); + assert.deepEqual([{ elements: arrayToRemove, removed: true }], target.args[0]); }); test('remove triggers change event', function () { @@ -243,13 +260,13 @@ suite('SearchResult', () => { testObject.add([ aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; testObject.onChange(target); - testObject.remove(objectRoRemove); + testObject.remove(objectToRemove); assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); }); test('Removing all line matches and adding back will add file back to result', function () { @@ -290,13 +307,13 @@ suite('SearchResult', () => { aRawMatch('file://c:/1', new TextSearchMatch('preview 1', lineOneRange))]); testObject.onChange(target); - const objectRoRemove = testObject.matches()[0]; + const objectToRemove = testObject.matches()[0]; - testObject.replace(objectRoRemove); + testObject.replace(objectToRemove); return voidPromise.then(() => { assert.ok(target.calledOnce); - assert.deepEqual([{ elements: [objectRoRemove], removed: true }], target.args[0]); + assert.deepEqual([{ elements: [objectToRemove], removed: true }], target.args[0]); }); }); diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts index f6b387c526..8124f75f21 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStats.ts @@ -319,12 +319,10 @@ export class WorkspaceStats implements IWorkbenchContribution { if (['DIRECT', 'PROXY', 'HTTPS', 'SOCKS', 'EMPTY'].indexOf(type) === -1) { type = 'UNKNOWN'; } - /* __GDPR__ - "resolveProxy.stats" : { - "type": { "classification": "SystemMetaData", "purpose": "PerformanceAndHealth" } - } - */ - this.telemetryService.publicLog('resolveProxy.stats', { type }); + type ResolveProxyStatsClassification = { + type: { classification: 'SystemMetaData', purpose: 'PerformanceAndHealth' }; + }; + this.telemetryService.publicLog2<{ type: String }, ResolveProxyStatsClassification>('resolveProxy.stats', { type }); }).then(undefined, onUnexpectedError); } } diff --git a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts index 18be93ac57..07d1e3f519 100644 --- a/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts +++ b/src/vs/workbench/contrib/stats/electron-browser/workspaceStatsService.ts @@ -47,7 +47,22 @@ const ModulesToLookFor = [ 'azure-storage', 'firebase', '@google-cloud/common', - 'heroku-cli' + 'heroku-cli', + //Office and Sharepoint packages + '@microsoft/office-js', + '@microsoft/office-js-helpers', + '@types/office-js', + '@types/office-runtime', + 'office-ui-fabric-react', + '@uifabric/icons', + '@uifabric/merge-styles', + '@uifabric/styling', + '@uifabric/experiments', + '@uifabric/utilities', + '@microsoft/rush', + 'lerna', + 'just-task', + 'beachball' ]; const PyModulesToLookFor = [ 'azure', @@ -143,6 +158,20 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.npm.@google-cloud/common" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.firebase" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.npm.heroku-cli" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/office-js-helpers" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-js" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@types/office-runtime" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.office-ui-fabric-react" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/icons" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/merge-styles" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/styling" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/experiments" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@uifabric/utilities" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.@microsoft/rush" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.lerna" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.just-task" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, + "workspace.npm.beachball" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.bower" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.yeoman.code.ext" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.cordova.high" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, @@ -188,7 +217,6 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { "workspace.py.botbuilder-core" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botbuilder-schema" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true }, "workspace.py.botframework-connector" : { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } */ private resolveWorkspaceTags(configuration: IWindowConfiguration, participant?: (rootFiles: string[]) => void): Promise { @@ -474,4 +502,4 @@ export class WorkspaceStatsService implements IWorkspaceStatsService { private searchArray(arr: string[], regEx: RegExp): boolean | undefined { return arr.some(v => v.search(regEx) > -1) || undefined; } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts index a909f45983..f4587c05cd 100644 --- a/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts +++ b/src/vs/workbench/contrib/tasks/browser/terminalTaskSystem.ts @@ -926,7 +926,7 @@ export class TerminalTaskSystem implements ITaskSystem { }; } else if (task.command.runtime === RuntimeType.CustomExecution2) { this.currentTask.shellLaunchConfig = launchConfigs = { - isVirtualProcess: true, + isExtensionTerminal: true, waitOnExit, name: this.createTerminalName(task, workspaceFolder), initialText: task.command.presentation && task.command.presentation.echo ? `\x1b[1m> Executing task: ${task._label} <\x1b[0m\n` : undefined diff --git a/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts new file mode 100644 index 0000000000..a47c6e6989 --- /dev/null +++ b/src/vs/workbench/contrib/terminal/browser/addons/navigationModeAddon.ts @@ -0,0 +1,106 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the Source EULA. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IContextKey } from 'vs/platform/contextkey/common/contextkey'; +import { Terminal, ITerminalAddon } from 'xterm'; +import { addDisposableListener } from 'vs/base/browser/dom'; +import { INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal'; + +export class NavigationModeAddon implements INavigationMode, ITerminalAddon { + private _terminal: Terminal; + + constructor( + private _navigationModeContextKey: IContextKey + ) { } + + activate(terminal: Terminal): void { + this._terminal = terminal; + } + + dispose() { } + + exitNavigationMode(): void { + this._terminal.scrollToBottom(); + this._terminal.focus(); + } + + focusPreviousLine(): void { + // Focus previous row if a row is already focused + if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) { + const element = document.activeElement.previousElementSibling; + if (element) { + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + return; + } + + // Ensure a11y tree exists + const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree'); + if (!treeContainer) { + return; + } + + // Target is row before the cursor + const targetRow = Math.max(this._terminal.buffer.cursorY - 1, 0); + + // Check bounds + if (treeContainer.childElementCount < targetRow) { + return; + } + + // Focus + const element = treeContainer.childNodes.item(targetRow); + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + + focusNextLine(): void { + // Focus previous row if a row is already focused + if (document.activeElement && document.activeElement.parentElement && document.activeElement.parentElement.classList.contains('xterm-accessibility-tree')) { + const element = document.activeElement.nextElementSibling; + if (element) { + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } + return; + } + + // Ensure a11y tree exists + const treeContainer = this._terminal.element.querySelector('.xterm-accessibility-tree'); + if (!treeContainer) { + return; + } + + // Target is cursor row + const targetRow = this._terminal.buffer.cursorY; + + // Check bounds + if (treeContainer.childElementCount < targetRow) { + return; + } + + // Focus row before cursor + const element = treeContainer.childNodes.item(targetRow); + element.focus(); + const disposable = addDisposableListener(element, 'blur', () => { + this._navigationModeContextKey.set(false); + disposable.dispose(); + }); + this._navigationModeContextKey.set(true); + } +} \ No newline at end of file diff --git a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts index f9111e0326..4ba2d5beb1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminal.contribution.ts @@ -20,10 +20,10 @@ import * as panel from 'vs/workbench/browser/panel'; import { getQuickNavigateHandler } from 'vs/workbench/browser/parts/quickopen/quickopen'; import { Extensions as QuickOpenExtensions, IQuickOpenRegistry, QuickOpenHandlerDescriptor } from 'vs/workbench/browser/quickopen'; import { Extensions as ActionExtensions, IWorkbenchActionRegistry } from 'vs/workbench/common/actions'; -import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand } from 'vs/workbench/contrib/terminal/browser/terminalActions'; +import { AllowWorkspaceShellTerminalCommand, ClearSelectionTerminalAction, ClearTerminalAction, CopyTerminalSelectionAction, CreateNewInActiveWorkspaceTerminalAction, CreateNewTerminalAction, DeleteToLineStartTerminalAction, DeleteWordLeftTerminalAction, DeleteWordRightTerminalAction, DisallowWorkspaceShellTerminalCommand, FindNext, FindPrevious, FocusActiveTerminalAction, FocusNextPaneTerminalAction, FocusNextTerminalAction, FocusPreviousPaneTerminalAction, FocusPreviousTerminalAction, FocusTerminalFindWidgetAction, HideTerminalFindWidgetAction, KillTerminalAction, MoveToLineEndTerminalAction, MoveToLineStartTerminalAction, QuickOpenActionTermContributor, QuickOpenTermAction, RenameTerminalAction, ResizePaneDownTerminalAction, ResizePaneLeftTerminalAction, ResizePaneRightTerminalAction, ResizePaneUpTerminalAction, RunActiveFileInTerminalAction, RunSelectedTextInTerminalAction, ScrollDownPageTerminalAction, ScrollDownTerminalAction, ScrollToBottomTerminalAction, ScrollToNextCommandAction, ScrollToPreviousCommandAction, ScrollToTopTerminalAction, ScrollUpPageTerminalAction, ScrollUpTerminalAction, SelectAllTerminalAction, SelectDefaultShellWindowsTerminalAction, SelectToNextCommandAction, SelectToNextLineAction, SelectToPreviousCommandAction, SelectToPreviousLineAction, SendSequenceTerminalCommand, SplitInActiveWorkspaceTerminalAction, SplitTerminalAction, TerminalPasteAction, TERMINAL_PICKER_PREFIX, ToggleCaseSensitiveCommand, ToggleEscapeSequenceLoggingAction, ToggleRegexCommand, ToggleTerminalAction, ToggleWholeWordCommand, NavigationModeFocusPreviousTerminalAction, NavigationModeFocusNextTerminalAction, NavigationModeExitTerminalAction } from 'vs/workbench/contrib/terminal/browser/terminalActions'; import { TerminalPanel } from 'vs/workbench/contrib/terminal/browser/terminalPanel'; import { TerminalPickerHandler } from 'vs/workbench/contrib/terminal/browser/terminalQuickOpen'; -import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY } from 'vs/workbench/contrib/terminal/common/terminal'; +import { KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_FOCUSED, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_NOT_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, TERMINAL_PANEL_ID, DEFAULT_LETTER_SPACING, DEFAULT_LINE_HEIGHT, TerminalCursorStyle, ITerminalService, TERMINAL_ACTION_CATEGORY, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS } from 'vs/workbench/contrib/terminal/common/terminal'; import { registerColors } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { setupTerminalCommands, TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { setupTerminalMenu } from 'vs/workbench/contrib/terminal/common/terminalMenu'; @@ -33,6 +33,7 @@ import { DEFAULT_COMMANDS_TO_SKIP_SHELL } from 'vs/workbench/contrib/terminal/br import { TerminalService } from 'vs/workbench/contrib/terminal/browser/terminalService'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { registerShellConfiguration } from 'vs/workbench/contrib/terminal/common/terminalShellConfig'; +import { CONTEXT_ACCESSIBILITY_MODE_ENABLED } from 'vs/platform/accessibility/common/accessibility'; registerSingleton(ITerminalService, TerminalService, true); @@ -459,6 +460,21 @@ actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextComm primary: 0, mac: { primary: KeyMod.CtrlCmd | KeyMod.Shift | KeyCode.DownArrow } }, KEYBINDING_CONTEXT_TERMINAL_FOCUS), 'Terminal: Select To Next Command', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeExitTerminalAction, NavigationModeExitTerminalAction.ID, NavigationModeExitTerminalAction.LABEL, { + primary: KeyCode.Escape +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Exit Navigation Mode', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.UpArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusPreviousTerminalAction, NavigationModeFocusPreviousTerminalAction.ID, NavigationModeFocusPreviousTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.UpArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Previous Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.DownArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); +actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(NavigationModeFocusNextTerminalAction, NavigationModeFocusNextTerminalAction.ID, NavigationModeFocusNextTerminalAction.LABEL, { + primary: KeyMod.CtrlCmd | KeyCode.DownArrow +}, ContextKeyExpr.and(KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, CONTEXT_ACCESSIBILITY_MODE_ENABLED)), 'Terminal: Focus Next Line (Navigation Mode)', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToPreviousLineAction, SelectToPreviousLineAction.ID, SelectToPreviousLineAction.LABEL), 'Terminal: Select To Previous Line', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(SelectToNextLineAction, SelectToNextLineAction.ID, SelectToNextLineAction.LABEL), 'Terminal: Select To Next Line', category); actionRegistry.registerWorkbenchAction(new SyncActionDescriptor(ToggleEscapeSequenceLoggingAction, ToggleEscapeSequenceLoggingAction.ID, ToggleEscapeSequenceLoggingAction.LABEL), 'Terminal: Toggle Escape Sequence Logging', category); diff --git a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts index cf5af3ae39..6f5d95122a 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalActions.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalActions.ts @@ -607,12 +607,11 @@ export class TerminalPasteAction extends Action { super(id, label); } - public run(event?: any): Promise { + public async run(event?: any): Promise { const instance = this.terminalService.getActiveOrCreateInstance(); if (instance) { - instance.paste(); + await instance.paste(); } - return Promise.resolve(undefined); } } @@ -749,6 +748,7 @@ export class SwitchTerminalActionViewItem extends SelectActionViewItem { this._register(terminalService.onInstancesChanged(this._updateItems, this)); this._register(terminalService.onActiveTabChanged(this._updateItems, this)); this._register(terminalService.onInstanceTitleChanged(this._updateItems, this)); + this._register(terminalService.onTabDisposed(this._updateItems, this)); this._register(attachSelectBoxStyler(this.selectBox, themeService)); } @@ -886,6 +886,71 @@ export class ScrollToTopTerminalAction extends Action { } } +export class NavigationModeExitTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeExit', "Exit Navigation Mode"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.exitNavigationMode(); + } + return Promise.resolve(undefined); + } +} + + + +export class NavigationModeFocusPreviousTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusPrevious', "Focus Previous Line (Navigation Mode)"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.focusPreviousLine(); + } + return Promise.resolve(undefined); + } +} + +export class NavigationModeFocusNextTerminalAction extends Action { + + public static readonly ID = TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT; + public static readonly LABEL = nls.localize('workbench.action.terminal.navigationModeFocusNext', "Focus Next Line (Navigation Mode)"); + + constructor( + id: string, label: string, + @ITerminalService private readonly terminalService: ITerminalService + ) { + super(id, label); + } + + public run(event?: any): Promise { + const terminalInstance = this.terminalService.getActiveInstance(); + if (terminalInstance && terminalInstance.navigationMode) { + terminalInstance.navigationMode.focusNextLine(); + } + return Promise.resolve(undefined); + } +} + export class ClearTerminalAction extends Action { public static readonly ID = TERMINAL_COMMAND_ID.CLEAR; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts index db48b025cf..049f2455c6 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalFindWidget.ts @@ -19,7 +19,7 @@ export class TerminalFindWidget extends SimpleFindWidget { @IContextKeyService private readonly _contextKeyService: IContextKeyService, @ITerminalService private readonly _terminalService: ITerminalService ) { - super(_contextViewService, _contextKeyService, findState, true); + super(_contextViewService, _contextKeyService, findState, true, true); this._register(findState.onFindReplaceStateChange(() => { this.show(); })); @@ -50,7 +50,7 @@ export class TerminalFindWidget extends SimpleFindWidget { // Ignore input changes for now const instance = this._terminalService.getActiveInstance(); if (instance !== null) { - return instance.findNext(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); + return instance.findPrevious(this.inputValue, { regex: this._getRegexValue(), wholeWord: this._getWholeWordValue(), caseSensitive: this._getCaseSensitiveValue(), incremental: true }); } return false; } @@ -78,4 +78,4 @@ export class TerminalFindWidget extends SimpleFindWidget { protected onFindInputFocusTrackerBlur() { this._findInputFocused.reset(); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts index b17e6101eb..393bd2b17f 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalInstance.ts @@ -25,7 +25,7 @@ import { activeContrastBorder, scrollbarSliderActiveBackground, scrollbarSliderB import { ICssStyleCollector, ITheme, IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService'; import { PANEL_BACKGROUND } from 'vs/workbench/common/theme'; import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/terminalWidgetManager'; -import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE } from 'vs/workbench/contrib/terminal/common/terminal'; +import { IShellLaunchConfig, ITerminalDimensions, ITerminalInstance, ITerminalProcessManager, KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED, NEVER_MEASURE_RENDER_TIME_STORAGE_KEY, ProcessState, TERMINAL_PANEL_ID, IWindowsShellHelper, SHELL_PATH_INVALID_EXIT_CODE, SHELL_PATH_DIRECTORY_EXIT_CODE, SHELL_CWD_INVALID_EXIT_CODE, KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS, INavigationMode } from 'vs/workbench/contrib/terminal/common/terminal'; import { ansiColorIdentifiers, TERMINAL_BACKGROUND_COLOR, TERMINAL_CURSOR_BACKGROUND_COLOR, TERMINAL_CURSOR_FOREGROUND_COLOR, TERMINAL_FOREGROUND_COLOR, TERMINAL_SELECTION_BACKGROUND_COLOR } from 'vs/workbench/contrib/terminal/common/terminalColorRegistry'; import { TERMINAL_COMMAND_ID } from 'vs/workbench/contrib/terminal/common/terminalCommands'; import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper'; @@ -35,8 +35,9 @@ import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; 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 { Terminal as XTermTerminal, IBuffer, ITerminalAddon } from 'xterm'; import { SearchAddon, ISearchOptions } from 'xterm-addon-search'; +import { NavigationModeAddon } from 'vs/workbench/contrib/terminal/browser/addons/navigationModeAddon'; // How long in milliseconds should an average frame take to render for a notification to appear // which suggests the fallback DOM-based renderer @@ -91,6 +92,9 @@ export const DEFAULT_COMMANDS_TO_SKIP_SHELL: string[] = [ TERMINAL_COMMAND_ID.SPLIT_IN_ACTIVE_WORKSPACE, TERMINAL_COMMAND_ID.SPLIT, TERMINAL_COMMAND_ID.TOGGLE, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_EXIT, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_NEXT, + TERMINAL_COMMAND_ID.NAVIGATION_MODE_FOCUS_PREVIOUS, 'editor.action.toggleTabFocusMode', 'workbench.action.quickOpen', 'workbench.action.quickOpenPreviousEditor', @@ -183,6 +187,7 @@ export class TerminalInstance implements ITerminalInstance { private _xtermSearch: SearchAddon | undefined; private _xtermElement: HTMLDivElement; private _terminalHasTextContextKey: IContextKey; + private _terminalA11yTreeFocusContextKey: IContextKey; private _cols: number; private _rows: number; private _dimensionsOverride: ITerminalDimensions | undefined; @@ -197,6 +202,7 @@ export class TerminalInstance implements ITerminalInstance { private _widgetManager: TerminalWidgetManager; private _linkHandler: TerminalLinkHandler; private _commandTracker: TerminalCommandTracker; + private _navigationModeAddon: INavigationMode & ITerminalAddon | undefined; public disableLayout: boolean; public get id(): number { return this._id; } @@ -224,6 +230,7 @@ export class TerminalInstance implements ITerminalInstance { public get isTitleSetByProcess(): boolean { return !!this._messageTitleDisposable; } public get shellLaunchConfig(): IShellLaunchConfig { return this._shellLaunchConfig; } public get commandTracker(): TerminalCommandTracker { return this._commandTracker; } + public get navigationMode(): INavigationMode | undefined { return this._navigationModeAddon; } private readonly _onExit = new Emitter(); public get onExit(): Event { return this._onExit.event; } @@ -280,6 +287,7 @@ export class TerminalInstance implements ITerminalInstance { }); this._terminalHasTextContextKey = KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED.bindTo(this._contextKeyService); + this._terminalA11yTreeFocusContextKey = KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS.bindTo(this._contextKeyService); this.disableLayout = false; this._logService.trace(`terminalInstance#ctor (id: ${this.id})`, this._shellLaunchConfig); @@ -462,13 +470,13 @@ export class TerminalInstance implements ITerminalInstance { letterSpacing: font.letterSpacing, lineHeight: font.lineHeight, bellStyle: config.enableBell ? 'sound' : 'none', - screenReaderMode: this._isScreenReaderOptimized(), macOptionIsMeta: config.macOptionIsMeta, macOptionClickForcesSelection: config.macOptionClickForcesSelection, rightClickSelectsWord: config.rightClickBehavior === 'selectWord', // TODO: Guess whether to use canvas or dom better rendererType: config.rendererType === 'auto' ? 'canvas' : config.rendererType }); + this.updateAccessibilitySupport(); this._terminalInstanceService.getXtermSearchConstructor().then(Addon => { this._xtermSearch = new Addon(); this._xterm.loadAddon(this._xtermSearch); @@ -861,9 +869,9 @@ export class TerminalInstance implements ITerminalInstance { return this._xtermReadyPromise.then(() => this.focus(force)); } - public paste(): void { + public async paste(): Promise { this.focus(); - document.execCommand('paste'); + this._xterm._core._coreService.triggerDataEvent(await this._clipboardService.readText(), true); } public write(text: string): void { @@ -958,7 +966,6 @@ export class TerminalInstance implements ITerminalInstance { private _refreshSelectionContextKey() { const activePanel = this._panelService.getActivePanel(); const isActive = !!activePanel && activePanel.getId() === TERMINAL_PANEL_ID; - this._terminalHasTextContextKey.set(isActive && this.hasSelection()); } @@ -968,6 +975,7 @@ export class TerminalInstance implements ITerminalInstance { this._processManager.onProcessExit(exitCode => this._onProcessExit(exitCode)); this._processManager.onProcessData(data => this._onData.fire(data)); this._processManager.onProcessOverrideDimensions(e => this.setDimensions(e)); + this._processManager.onProcessResolvedShellLaunchConfig(e => this._setResolvedShellLaunchConfig(e)); if (this._shellLaunchConfig.name) { this.setTitle(this._shellLaunchConfig.name, false); @@ -1223,7 +1231,17 @@ export class TerminalInstance implements ITerminalInstance { } public updateAccessibilitySupport(): void { - this._xterm.setOption('screenReaderMode', this._isScreenReaderOptimized()); + const isEnabled = this._isScreenReaderOptimized(); + if (isEnabled) { + this._navigationModeAddon = new NavigationModeAddon(this._terminalA11yTreeFocusContextKey); + this._xterm.loadAddon(this._navigationModeAddon); + } else { + if (this._navigationModeAddon) { + this._navigationModeAddon.dispose(); + this._navigationModeAddon = undefined; + } + } + this._xterm.setOption('screenReaderMode', isEnabled); } private _setCursorBlink(blink: boolean): void { @@ -1379,6 +1397,13 @@ export class TerminalInstance implements ITerminalInstance { this._resize(); } + private _setResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { + this._shellLaunchConfig.args = shellLaunchConfig.args; + this._shellLaunchConfig.cwd = shellLaunchConfig.cwd; + this._shellLaunchConfig.executable = shellLaunchConfig.executable; + this._shellLaunchConfig.env = shellLaunchConfig.env; + } + private _getXtermTheme(theme?: ITheme): any { if (!theme) { theme = this._themeService.getTheme(); @@ -1420,8 +1445,7 @@ export class TerminalInstance implements ITerminalInstance { } public toggleEscapeSequenceLogging(): void { - this._xterm._core.debug = !this._xterm._core.debug; - this._xterm.setOption('debug', this._xterm._core.debug); + this._xterm.setOption('logLevel', 'debug'); } public getInitialCwd(): Promise { diff --git a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts index ac65eb4c58..076eff6fb1 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalProcessManager.ts @@ -31,7 +31,7 @@ const LATENCY_MEASURING_INTERVAL = 1000; enum ProcessType { Process, - VirtualProcess + ExtensionTerminal } /** @@ -70,6 +70,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { public get onProcessExit(): Event { return this._onProcessExit.event; } private readonly _onProcessOverrideDimensions = new Emitter(); public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + private readonly _onProcessOverrideShellLaunchConfig = new Emitter(); + public get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessOverrideShellLaunchConfig.event; } constructor( private readonly _terminalId: number, @@ -111,8 +113,8 @@ export class TerminalProcessManager implements ITerminalProcessManager { rows: number, isScreenReaderModeEnabled: boolean ): Promise { - if (shellLaunchConfig.isVirtualProcess) { - this._processType = ProcessType.VirtualProcess; + if (shellLaunchConfig.isExtensionTerminal) { + this._processType = ProcessType.ExtensionTerminal; this._process = this._instantiationService.createInstance(TerminalProcessExtHostProxy, this._terminalId, shellLaunchConfig, undefined, cols, rows, this._configHelper); } else { const forceExtHostProcess = (this._configHelper.config as any).extHostProcess; @@ -170,6 +172,9 @@ export class TerminalProcessManager implements ITerminalProcessManager { if (this._process.onProcessOverrideDimensions) { this._process.onProcessOverrideDimensions(e => this._onProcessOverrideDimensions.fire(e)); } + if (this._process.onProcessResolvedShellLaunchConfig) { + this._process.onProcessResolvedShellLaunchConfig(e => this._onProcessOverrideShellLaunchConfig.fire(e)); + } setTimeout(() => { if (this.processState === ProcessState.LAUNCHING) { @@ -234,7 +239,7 @@ export class TerminalProcessManager implements ITerminalProcessManager { } public write(data: string): void { - if (this.shellProcessId || this._processType === ProcessType.VirtualProcess) { + if (this.shellProcessId || this._processType === ProcessType.ExtensionTerminal) { if (this._process) { // Send data if the pty is ready this._process.input(data); @@ -287,4 +292,4 @@ export class TerminalProcessManager implements ITerminalProcessManager { this._onProcessExit.fire(exitCode); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/browser/terminalService.ts b/src/vs/workbench/contrib/terminal/browser/terminalService.ts index f96142ab94..ceba74cb1c 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalService.ts @@ -49,7 +49,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS this._configHelper = this._instantiationService.createInstance(TerminalConfigHelper, this.terminalNativeService.linuxDistro); } - public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance { + public createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance { const instance = this._instantiationService.createInstance(TerminalInstance, terminalFocusContextKey, configHelper, container, shellLaunchConfig); this._onInstanceCreated.fire(instance); return instance; @@ -60,8 +60,7 @@ export class TerminalService extends CommonTerminalService implements ITerminalS const instance = this.createInstance(this._terminalFocusContextKey, this.configHelper, undefined, - shell, - true); + shell); this._backgroundedTerminalInstances.push(instance); this._initInstanceListeners(instance); return instance; diff --git a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts index 61fcbd67c5..3ee8f4cf16 100644 --- a/src/vs/workbench/contrib/terminal/browser/terminalTab.ts +++ b/src/vs/workbench/contrib/terminal/browser/terminalTab.ts @@ -246,8 +246,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { terminalFocusContextKey, configHelper, undefined, - shellLaunchConfigOrInstance, - true); + shellLaunchConfigOrInstance); } this._terminalInstances.push(instance); this._initInstanceListeners(instance); @@ -389,8 +388,7 @@ export class TerminalTab extends Disposable implements ITerminalTab { terminalFocusContextKey, configHelper, undefined, - shellLaunchConfig, - true); + shellLaunchConfig); this._terminalInstances.splice(this._activeInstanceIndex + 1, 0, instance); this._initInstanceListeners(instance); this._setActiveInstance(instance); diff --git a/src/vs/workbench/contrib/terminal/common/terminal.ts b/src/vs/workbench/contrib/terminal/common/terminal.ts index b84a051c63..db75dd8ddc 100644 --- a/src/vs/workbench/contrib/terminal/common/terminal.ts +++ b/src/vs/workbench/contrib/terminal/common/terminal.ts @@ -21,6 +21,8 @@ export const KEYBINDING_CONTEXT_TERMINAL_IS_OPEN = new RawContextKey('t export const KEYBINDING_CONTEXT_TERMINAL_FOCUS = new RawContextKey('terminalFocus', false); /** A context key that is set when the integrated terminal does not have focus. */ export const KEYBINDING_CONTEXT_TERMINAL_NOT_FOCUSED: ContextKeyExpr = KEYBINDING_CONTEXT_TERMINAL_FOCUS.toNegated(); +/** A context key that is set when the user is navigating the accessibility tree */ +export const KEYBINDING_CONTEXT_TERMINAL_A11Y_TREE_FOCUS = new RawContextKey('terminalA11yTreeFocus', false); /** A keybinding context key that is set when the integrated terminal has text selected. */ export const KEYBINDING_CONTEXT_TERMINAL_TEXT_SELECTED = new RawContextKey('terminalTextSelected', false); @@ -186,14 +188,14 @@ export interface IShellLaunchConfig { initialText?: string; /** - * @deprecated use `isVirtualProcess` + * @deprecated use `isExtensionTerminal` */ isRendererOnly?: boolean; /** - * When true an extension is acting as the terminal's process. + * Whether an extension is controlling the terminal via a `vscode.Pseudoterminal`. */ - isVirtualProcess?: boolean; + isExtensionTerminal?: boolean; /** * Whether the terminal process environment should be exactly as provided in @@ -229,8 +231,8 @@ export interface ITerminalService { onInstanceProcessIdReady: Event; onInstanceDimensionsChanged: Event; onInstanceMaximumDimensionsChanged: Event; - onInstanceRequestExtHostProcess: Event; - onInstanceRequestVirtualProcess: Event; + onInstanceRequestSpawnExtHostProcess: Event; + onInstanceRequestStartExtensionTerminal: Event; onInstancesChanged: Event; onInstanceTitleChanged: Event; onActiveInstanceChanged: Event; @@ -251,7 +253,7 @@ export interface ITerminalService { /** * Creates a raw terminal instance, this should not be used outside of the terminal part. */ - createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig, doCreateProcess: boolean): ITerminalInstance; + createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement | undefined, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; getInstanceFromId(terminalId: number): ITerminalInstance | undefined; getInstanceFromIndex(terminalIndex: number): ITerminalInstance; getTabLabels(): string[]; @@ -297,8 +299,8 @@ export interface ITerminalService { preparePathForTerminalAsync(path: string, executable: string | undefined, title: string): Promise; extHostReady(remoteAuthority: string): void; - requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; - requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; + requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void; + requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void; } /** @@ -483,6 +485,8 @@ export interface ITerminalInstance { */ readonly commandTracker: ITerminalCommandTracker; + readonly navigationMode: INavigationMode | undefined; + /** * Dispose the terminal instance, removing it from the panel/service and freeing up resources. * @@ -584,7 +588,7 @@ export interface ITerminalInstance { /** * Focuses and pastes the contents of the clipboard into the terminal instance. */ - paste(): void; + paste(): Promise; /** * Send text to the terminal instance. The text is written to the stdin of the underlying pty @@ -629,17 +633,6 @@ export interface ITerminalInstance { */ attachToElement(container: HTMLElement): void; - /** - * Updates the configuration of the terminal instance. - */ - updateConfig(): void; - - /** - * Updates the accessibility support state of the terminal instance. - * @param isEnabled Whether it's enabled. - */ - updateAccessibilitySupport(isEnabled: boolean): void; - /** * Configure the dimensions of the terminal instance. * @@ -687,6 +680,12 @@ export interface ITerminalCommandTracker { selectToNextLine(): void; } +export interface INavigationMode { + exitNavigationMode(): void; + focusPreviousLine(): void; + focusNextLine(): void; +} + export interface IBeforeProcessDataEvent { /** * The data of the event, this can be modified by the event listener to change what gets sent @@ -709,6 +708,7 @@ export interface ITerminalProcessManager extends IDisposable { readonly onProcessTitle: Event; readonly onProcessExit: Event; readonly onProcessOverrideDimensions: Event; + readonly onProcessResolvedShellLaunchConfig: Event; dispose(immediate?: boolean): void; createProcess(shellLaunchConfig: IShellLaunchConfig, cols: number, rows: number, isScreenReaderModeEnabled: boolean): Promise; @@ -747,6 +747,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { emitReady(pid: number, cwd: string): void; emitExit(exitCode: number): void; emitOverrideDimensions(dimensions: ITerminalDimensions | undefined): void; + emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void; emitInitialCwd(initialCwd: string): void; emitCwd(cwd: string): void; emitLatency(latency: number): void; @@ -759,7 +760,7 @@ export interface ITerminalProcessExtHostProxy extends IDisposable { onRequestLatency: Event; } -export interface ITerminalProcessExtHostRequest { +export interface ISpawnExtHostProcessRequest { proxy: ITerminalProcessExtHostProxy; shellLaunchConfig: IShellLaunchConfig; activeWorkspaceRootUri: URI; @@ -768,7 +769,7 @@ export interface ITerminalProcessExtHostRequest { isWorkspaceShellAllowed: boolean; } -export interface ITerminalVirtualProcessRequest { +export interface IStartExtensionTerminalRequest { proxy: ITerminalProcessExtHostProxy; cols: number; rows: number; @@ -802,6 +803,7 @@ export interface ITerminalChildProcess { onProcessReady: Event<{ pid: number, cwd: string }>; onProcessTitleChanged: Event; onProcessOverrideDimensions?: Event; + onProcessResolvedShellLaunchConfig?: Event; /** * Shutdown the terminal process. diff --git a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts b/src/vs/workbench/contrib/terminal/common/terminalCommands.ts index 7e1e779706..347d0b3072 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalCommands.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalCommands.ts @@ -68,6 +68,9 @@ export const enum TERMINAL_COMMAND_ID { TOGGLE_FIND_REGEX_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindRegexTerminalFocus', TOGGLE_FIND_WHOLE_WORD_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindWholeWordTerminalFocus', TOGGLE_FIND_CASE_SENSITIVE_TERMINAL_FOCUS = 'workbench.action.terminal.toggleFindCaseSensitiveTerminalFocus', + NAVIGATION_MODE_EXIT = 'workbench.action.terminal.navigationModeExit', + NAVIGATION_MODE_FOCUS_NEXT = 'workbench.action.terminal.navigationModeFocusNext', + NAVIGATION_MODE_FOCUS_PREVIOUS = 'workbench.action.terminal.navigationModeFocusPrevious' } export function setupTerminalCommands(): void { diff --git a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts index 8a17e218dc..46c1a1bb77 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalEnvironment.ts @@ -106,6 +106,7 @@ function _getLangEnvVariable(locale?: string) { ko: 'KR', pl: 'PL', ru: 'RU', + sk: 'SK', zh: 'CN' }; if (parts[0] in languageVariants) { diff --git a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts index c178274d58..10da7571df 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalProcessExtHostProxy.ts @@ -24,6 +24,8 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal public readonly onProcessTitleChanged: Event = this._onProcessTitleChanged.event; private readonly _onProcessOverrideDimensions = new Emitter(); public get onProcessOverrideDimensions(): Event { return this._onProcessOverrideDimensions.event; } + private readonly _onProcessResolvedShellLaunchConfig = new Emitter(); + public get onProcessResolvedShellLaunchConfig(): Event { return this._onProcessResolvedShellLaunchConfig.event; } private readonly _onInput = this._register(new Emitter()); public readonly onInput: Event = this._onInput.event; @@ -56,14 +58,14 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal // Request a process if needed, if this is a virtual process this step can be skipped as // there is no real "process" and we know it's ready on the ext host already. - if (shellLaunchConfig.isVirtualProcess) { - this._terminalService.requestVirtualProcess(this, cols, rows); + if (shellLaunchConfig.isExtensionTerminal) { + this._terminalService.requestStartExtensionTerminal(this, cols, rows); } else { remoteAgentService.getEnvironment().then(env => { if (!env) { throw new Error('Could not fetch environment'); } - this._terminalService.requestExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); + this._terminalService.requestSpawnExtHostProcess(this, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, configHelper.checkWorkspaceShellPermissions(env.os)); }); if (!hasReceivedResponse) { setTimeout(() => this._onProcessTitleChanged.fire(nls.localize('terminal.integrated.starting', "Starting...")), 0); @@ -93,6 +95,10 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._onProcessOverrideDimensions.fire(dimensions); } + public emitResolvedShellLaunchConfig(shellLaunchConfig: IShellLaunchConfig): void { + this._onProcessResolvedShellLaunchConfig.fire(shellLaunchConfig); + } + public emitInitialCwd(initialCwd: string): void { while (this._pendingInitialCwdRequests.length > 0) { this._pendingInitialCwdRequests.pop()!(initialCwd); @@ -143,4 +149,4 @@ export class TerminalProcessExtHostProxy extends Disposable implements ITerminal this._pendingLatencyRequests.push(resolve); }); } -} \ No newline at end of file +} diff --git a/src/vs/workbench/contrib/terminal/common/terminalService.ts b/src/vs/workbench/contrib/terminal/common/terminalService.ts index 0abc34843c..d66b9c5d40 100644 --- a/src/vs/workbench/contrib/terminal/common/terminalService.ts +++ b/src/vs/workbench/contrib/terminal/common/terminalService.ts @@ -8,7 +8,7 @@ import { Event, Emitter } from 'vs/base/common/event'; import { IContextKeyService, IContextKey } from 'vs/platform/contextkey/common/contextkey'; import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IPanelService } from 'vs/workbench/services/panel/common/panelService'; -import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ITerminalProcessExtHostRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, ITerminalVirtualProcessRequest } from 'vs/workbench/contrib/terminal/common/terminal'; +import { ITerminalService, ITerminalInstance, IShellLaunchConfig, ITerminalConfigHelper, KEYBINDING_CONTEXT_TERMINAL_FOCUS, KEYBINDING_CONTEXT_TERMINAL_FIND_WIDGET_VISIBLE, TERMINAL_PANEL_ID, ITerminalTab, ITerminalProcessExtHostProxy, ISpawnExtHostProcessRequest, KEYBINDING_CONTEXT_TERMINAL_IS_OPEN, ITerminalNativeService, IShellDefinition, IAvailableShellsRequest, IStartExtensionTerminalRequest } from 'vs/workbench/contrib/terminal/common/terminal'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { URI } from 'vs/base/common/uri'; import { FindReplaceState } from 'vs/editor/contrib/find/findState'; @@ -20,11 +20,15 @@ import { escapeNonWindowsPath } from 'vs/workbench/contrib/terminal/common/termi import { isWindows, isMacintosh, OperatingSystem } from 'vs/base/common/platform'; import { basename } from 'vs/base/common/path'; import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; -import { timeout } from 'vs/base/common/async'; import { IOpenFileRequest } from 'vs/platform/windows/common/windows'; import { IPickOptions, IQuickPickItem, IQuickInputService } from 'vs/platform/quickinput/common/quickInput'; import { IConfigurationService, ConfigurationTarget } from 'vs/platform/configuration/common/configuration'; +interface IExtHostReadyEntry { + promise: Promise; + resolve: () => void; +} + export abstract class TerminalService implements ITerminalService { public _serviceBrand: any; @@ -38,7 +42,7 @@ export abstract class TerminalService implements ITerminalService { return this._terminalTabs.reduce((p, c) => p.concat(c.terminalInstances), []); } private _findState: FindReplaceState; - private _extHostsReady: { [authority: string]: boolean } = {}; + private _extHostsReady: { [authority: string]: IExtHostReadyEntry | undefined } = {}; private _activeTabIndex: number; public get activeTabIndex(): number { return this._activeTabIndex; } @@ -53,10 +57,10 @@ export abstract class TerminalService implements ITerminalService { public get onInstanceDisposed(): Event { return this._onInstanceDisposed.event; } protected readonly _onInstanceProcessIdReady = new Emitter(); public get onInstanceProcessIdReady(): Event { return this._onInstanceProcessIdReady.event; } - protected readonly _onInstanceRequestExtHostProcess = new Emitter(); - public get onInstanceRequestExtHostProcess(): Event { return this._onInstanceRequestExtHostProcess.event; } - protected readonly _onInstanceRequestVirtualProcess = new Emitter(); - public get onInstanceRequestVirtualProcess(): Event { return this._onInstanceRequestVirtualProcess.event; } + protected readonly _onInstanceRequestSpawnExtHostProcess = new Emitter(); + public get onInstanceRequestSpawnExtHostProcess(): Event { return this._onInstanceRequestSpawnExtHostProcess.event; } + protected readonly _onInstanceRequestStartExtensionTerminal = new Emitter(); + public get onInstanceRequestStartExtensionTerminal(): Event { return this._onInstanceRequestStartExtensionTerminal.event; } protected readonly _onInstanceDimensionsChanged = new Emitter(); public get onInstanceDimensionsChanged(): Event { return this._onInstanceDimensionsChanged.event; } protected readonly _onInstanceMaximumDimensionsChanged = new Emitter(); @@ -119,7 +123,7 @@ export abstract class TerminalService implements ITerminalService { protected abstract _showBackgroundTerminal(instance: ITerminalInstance): 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 createInstance(terminalFocusContextKey: IContextKey, configHelper: ITerminalConfigHelper, container: HTMLElement, shellLaunchConfig: IShellLaunchConfig): ITerminalInstance; public abstract setContainers(panelContainer: HTMLElement, terminalContainer: HTMLElement): void; public createTerminalRenderer(name: string): ITerminalInstance { @@ -131,26 +135,39 @@ export abstract class TerminalService implements ITerminalService { return activeInstance ? activeInstance : this.createTerminal(undefined, wasNewTerminalAction); } - public requestExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { + public requestSpawnExtHostProcess(proxy: ITerminalProcessExtHostProxy, shellLaunchConfig: IShellLaunchConfig, activeWorkspaceRootUri: URI, cols: number, rows: number, isWorkspaceShellAllowed: boolean): void { this._extensionService.whenInstalledExtensionsRegistered().then(async () => { - // Wait for the remoteAuthority to be ready (and listening for events) before proceeding + // Wait for the remoteAuthority to be ready (and listening for events) before firing + // the event to spawn the ext host process const conn = this._remoteAgentService.getConnection(); const remoteAuthority = conn ? conn.remoteAuthority : 'null'; - let retries = 0; - while (!this._extHostsReady[remoteAuthority] && ++retries < 50) { - await timeout(100); - } - this._onInstanceRequestExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); + await this._whenExtHostReady(remoteAuthority); + this._onInstanceRequestSpawnExtHostProcess.fire({ proxy, shellLaunchConfig, activeWorkspaceRootUri, cols, rows, isWorkspaceShellAllowed }); }); } - public requestVirtualProcess(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { - // Don't need to wait on extensions here as this can only be triggered by an extension - this._onInstanceRequestVirtualProcess.fire({ proxy, cols, rows }); + public requestStartExtensionTerminal(proxy: ITerminalProcessExtHostProxy, cols: number, rows: number): void { + this._onInstanceRequestStartExtensionTerminal.fire({ proxy, cols, rows }); } - public extHostReady(remoteAuthority: string): void { - this._extHostsReady[remoteAuthority] = true; + public async extHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + this._extHostsReady[remoteAuthority]!.resolve(); + } + + private async _whenExtHostReady(remoteAuthority: string): Promise { + this._createExtHostReadyEntry(remoteAuthority); + return this._extHostsReady[remoteAuthority]!.promise; + } + + private _createExtHostReadyEntry(remoteAuthority: string): void { + if (this._extHostsReady[remoteAuthority]) { + return; + } + + let resolve!: () => void; + const promise = new Promise(r => resolve = r); + this._extHostsReady[remoteAuthority] = { promise, resolve }; } private _onBeforeShutdown(): boolean | Promise { diff --git a/src/vs/workbench/contrib/update/electron-browser/update.ts b/src/vs/workbench/contrib/update/electron-browser/update.ts index 0a20efa4a0..e2e91d8220 100644 --- a/src/vs/workbench/contrib/update/electron-browser/update.ts +++ b/src/vs/workbench/contrib/update/electron-browser/update.ts @@ -30,6 +30,7 @@ import { MenuRegistry, MenuId } from 'vs/platform/actions/common/actions'; import { CommandsRegistry } from 'vs/platform/commands/common/commands'; import { FalseContext } from 'vs/platform/contextkey/common/contextkeys'; import { ShowCurrentReleaseNotesActionId } from 'vs/workbench/contrib/update/common/update'; +import { IWindowService, IWindowsService } from 'vs/platform/windows/common/windows'; const CONTEXT_UPDATE_STATE = new RawContextKey('updateState', StateType.Uninitialized); @@ -123,40 +124,44 @@ export class ProductContribution implements IWorkbenchContribution { @INotificationService notificationService: INotificationService, @IEnvironmentService environmentService: IEnvironmentService, @IOpenerService openerService: IOpenerService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IWindowService windowService: IWindowService, + @IWindowsService windowsService: IWindowsService ) { - // {{SQL CARBON EDIT}} - /* - const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); - const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); + /* windowsService.getActiveWindowId().then(async windowId => { {{SQL CARBON EDIT}} comment out + if (windowId !== windowService.windowId) { + return; + } - // was there an update? if so, open release notes - if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) { - showReleaseNotes(instantiationService, pkg.version) - .then(undefined, () => { - notificationService.prompt( - severity.Info, - nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", product.nameLong, pkg.version), - [{ - label: nls.localize('releaseNotes', "Release Notes"), - run: () => { - const uri = URI.parse(product.releaseNotesUrl); - openerService.open(uri); - } - }], - { sticky: true } - ); - }); - } + const lastVersion = storageService.get(ProductContribution.KEY, StorageScope.GLOBAL, ''); + const shouldShowReleaseNotes = configurationService.getValue('update.showReleaseNotes'); - // should we show the new license? - if (product.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(pkg.version, '>=1.0.0')) { - notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", product.licenseUrl)); - } + // was there an update? if so, open release notes + if (shouldShowReleaseNotes && !environmentService.skipReleaseNotes && product.releaseNotesUrl && lastVersion && pkg.version !== lastVersion) { + showReleaseNotes(instantiationService, pkg.version) + .then(undefined, () => { + notificationService.prompt( + severity.Info, + nls.localize('read the release notes', "Welcome to {0} v{1}! Would you like to read the Release Notes?", product.nameLong, pkg.version), + [{ + label: nls.localize('releaseNotes', "Release Notes"), + run: () => { + const uri = URI.parse(product.releaseNotesUrl); + openerService.open(uri); + } + }], + { sticky: true } + ); + }); + } - storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL); - // {{SQL CARBON EDIT}} - */ + // should we show the new license? + if (product.licenseUrl && lastVersion && semver.satisfies(lastVersion, '<1.0.0') && semver.satisfies(pkg.version, '>=1.0.0')) { + notificationService.info(nls.localize('licenseChanged', "Our license terms have changed, please click [here]({0}) to go through them.", product.licenseUrl)); + } + + storageService.store(ProductContribution.KEY, pkg.version, StorageScope.GLOBAL); + });*/ } } diff --git a/src/vs/workbench/contrib/watermark/browser/watermark.ts b/src/vs/workbench/contrib/watermark/browser/watermark.ts index ed9bdc01ea..284e3bb593 100644 --- a/src/vs/workbench/contrib/watermark/browser/watermark.ts +++ b/src/vs/workbench/contrib/watermark/browser/watermark.ts @@ -191,7 +191,7 @@ export class WatermarkContribution extends Disposable implements IWorkbenchContr 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.handleEditorPartSize(container, this.editorGroupsService.dimension); + this.handleEditorPartSize(container, this.editorGroupsService.contentDimension); } private handleEditorPartSize(container: HTMLElement, dimension: IDimension): void { diff --git a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts index 085d9b45dc..30f60bec8a 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewEditorService.ts @@ -90,7 +90,7 @@ export function areWebviewInputOptionsEqual(a: WebviewInputOptions, b: WebviewIn && a.retainContextWhenHidden === b.retainContextWhenHidden && a.tryRestoreScrollPosition === b.tryRestoreScrollPosition && (a.localResourceRoots === b.localResourceRoots || (Array.isArray(a.localResourceRoots) && Array.isArray(b.localResourceRoots) && equals(a.localResourceRoots, b.localResourceRoots, (a, b) => a.toString() === b.toString()))) - && (a.portMappings === b.portMappings || (Array.isArray(a.portMappings) && Array.isArray(b.portMappings) && equals(a.portMappings, b.portMappings, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); + && (a.portMapping === b.portMapping || (Array.isArray(a.portMapping) && Array.isArray(b.portMapping) && equals(a.portMapping, b.portMapping, (a, b) => a.extensionHostPort === b.extensionHostPort && a.webviewPort === b.webviewPort))); } function canRevive(reviver: WebviewReviver, webview: WebviewEditorInput): boolean { diff --git a/src/vs/workbench/contrib/webview/browser/webviewElement.ts b/src/vs/workbench/contrib/webview/browser/webviewElement.ts index f54e53635d..da4d1bb6c5 100644 --- a/src/vs/workbench/contrib/webview/browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/browser/webviewElement.ts @@ -53,7 +53,7 @@ export class IFrameWebview extends Disposable implements Webview { this._portMappingManager = this._register(new WebviewPortMappingManager( this._options.extension ? this._options.extension.location : undefined, - () => this.content.options.portMappings || [], + () => this.content.options.portMapping || [], tunnelService )); diff --git a/src/vs/workbench/contrib/webview/common/webview.ts b/src/vs/workbench/contrib/webview/common/webview.ts index 2b584fd092..7136acca40 100644 --- a/src/vs/workbench/contrib/webview/common/webview.ts +++ b/src/vs/workbench/contrib/webview/common/webview.ts @@ -55,7 +55,7 @@ export interface WebviewContentOptions { readonly allowScripts?: boolean; readonly svgWhiteList?: string[]; readonly localResourceRoots?: ReadonlyArray; - readonly portMappings?: ReadonlyArray; + readonly portMapping?: ReadonlyArray; readonly enableCommandUris?: boolean; } diff --git a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts index 4a2d2bb9ec..055bf76361 100644 --- a/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts +++ b/src/vs/workbench/contrib/webview/electron-browser/webviewElement.ts @@ -327,7 +327,7 @@ export class ElectronWebviewBasedWebview extends Disposable implements Webview { this._register(new WebviewPortMappingProvider( session, _options.extension ? _options.extension.location : undefined, - () => (this.content.options.portMappings || []), + () => (this.content.options.portMapping || []), tunnelService, )); diff --git a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts index c794c3c8c8..b94381e080 100644 --- a/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts +++ b/src/vs/workbench/contrib/welcome/walkThrough/browser/walkThroughPart.ts @@ -301,12 +301,6 @@ export class WalkThroughPart extends BaseEditor { const div = innerContent.querySelector(`#${id.replace(/\./g, '\\.')}`) as HTMLElement; const options = this.getEditorOptions(snippet.textEditorModel.getModeId()); - /* __GDPR__FRAGMENT__ - "EditorTelemetryData" : { - "target" : { "classification": "SystemMetaData", "purpose": "FeatureInsight" }, - "snippet": { "classification": "SystemMetaData", "purpose": "FeatureInsight", "isMeasurement": true } - } - */ const telemetryData = { target: this.input instanceof WalkThroughInput ? this.input.getTelemetryFrom() : undefined, snippet: i diff --git a/src/vs/workbench/services/accessibility/node/accessibilityService.ts b/src/vs/workbench/services/accessibility/node/accessibilityService.ts index 97a9767487..91b0058663 100644 --- a/src/vs/workbench/services/accessibility/node/accessibilityService.ts +++ b/src/vs/workbench/services/accessibility/node/accessibilityService.ts @@ -5,19 +5,23 @@ import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; import { isWindows } from 'vs/base/common/platform'; -import { Emitter, Event } from 'vs/base/common/event'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; +import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { AbstractAccessibilityService } from 'vs/platform/accessibility/common/abstractAccessibilityService'; -export class AccessibilityService implements IAccessibilityService { +export class AccessibilityService extends AbstractAccessibilityService implements IAccessibilityService { _serviceBrand: any; private _accessibilitySupport = AccessibilitySupport.Unknown; - private readonly _onDidChangeAccessibilitySupport = new Emitter(); - readonly onDidChangeAccessibilitySupport: Event = this._onDidChangeAccessibilitySupport.event; constructor( - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { } + @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService, + @IContextKeyService readonly contextKeyService: IContextKeyService, + @IConfigurationService readonly configurationService: IConfigurationService + ) { + super(contextKeyService, configurationService); + } alwaysUnderlineAccessKeys(): Promise { if (!isWindows) { diff --git a/src/vs/workbench/services/commands/common/commandService.ts b/src/vs/workbench/services/commands/common/commandService.ts index 4cdbea12c2..7d5801ef04 100644 --- a/src/vs/workbench/services/commands/common/commandService.ts +++ b/src/vs/workbench/services/commands/common/commandService.ts @@ -22,6 +22,9 @@ export class CommandService extends Disposable implements ICommandService { private readonly _onWillExecuteCommand: Emitter = this._register(new Emitter()); public readonly onWillExecuteCommand: Event = this._onWillExecuteCommand.event; + private readonly _onDidExecuteCommand: Emitter = new Emitter(); + public readonly onDidExecuteCommand: Event = this._onDidExecuteCommand.event; + constructor( @IInstantiationService private readonly _instantiationService: IInstantiationService, @IExtensionService private readonly _extensionService: IExtensionService, @@ -77,8 +80,9 @@ export class CommandService extends Disposable implements ICommandService { return Promise.reject(new Error(`command '${id}' not found`)); } try { - this._onWillExecuteCommand.fire({ commandId: id }); + this._onWillExecuteCommand.fire({ commandId: id, args }); const result = this._instantiationService.invokeFunction.apply(this._instantiationService, [command.handler, ...args]); + this._onDidExecuteCommand.fire({ commandId: id, args }); return Promise.resolve(result); } catch (err) { return Promise.reject(err); diff --git a/src/vs/workbench/services/configuration/browser/configuration.ts b/src/vs/workbench/services/configuration/browser/configuration.ts index 6355ce2e2b..35888ab8f2 100644 --- a/src/vs/workbench/services/configuration/browser/configuration.ts +++ b/src/vs/workbench/services/configuration/browser/configuration.ts @@ -12,7 +12,7 @@ import { RunOnceScheduler } from 'vs/base/common/async'; import { FileChangeType, FileChangesEvent, IFileService } from 'vs/platform/files/common/files'; import { ConfigurationModel, ConfigurationModelParser } from 'vs/platform/configuration/common/configurationModels'; import { WorkspaceConfigurationModelParser, StandaloneConfigurationModelParser } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_SETTINGS_PATH, TASKS_CONFIGURATION_KEY, FOLDER_SETTINGS_NAME, LAUNCH_CONFIGURATION_KEY, IConfigurationCache, ConfigurationKey, REMOTE_MACHINE_SCOPES, FOLDER_SCOPES, WORKSPACE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { IStoredWorkspaceFolder, IWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces'; import { JSONEditingService } from 'vs/workbench/services/configuration/common/jsonEditingService'; import { WorkbenchState, IWorkspaceFolder } from 'vs/platform/workspace/common/workspace'; @@ -24,6 +24,20 @@ import { IConfigurationModel } from 'vs/platform/configuration/common/configurat import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { hash } from 'vs/base/common/hash'; +function whenProviderRegistered(scheme: string, fileService: IFileService): Promise { + if (fileService.canHandleResource(URI.from({ scheme }))) { + return Promise.resolve(); + } + return new Promise((c, e) => { + const disposable = fileService.onDidChangeFileSystemProviderRegistrations(e => { + if (e.scheme === scheme && e.added) { + disposable.dispose(); + c(); + } + }); + }); +} + export class UserConfiguration extends Disposable { private readonly parser: ConfigurationModelParser; @@ -66,7 +80,7 @@ export class UserConfiguration extends Disposable { export class RemoteUserConfiguration extends Disposable { private readonly _cachedConfiguration: CachedRemoteUserConfiguration; - private readonly _configurationFileService: ConfigurationFileService; + private readonly _fileService: IFileService; private _userConfiguration: FileServiceBasedRemoteUserConfiguration | CachedRemoteUserConfiguration; private _userConfigurationInitializationPromise: Promise | null = null; @@ -76,15 +90,15 @@ export class RemoteUserConfiguration extends Disposable { constructor( remoteAuthority: string, configurationCache: IConfigurationCache, - configurationFileService: ConfigurationFileService, + fileService: IFileService, remoteAgentService: IRemoteAgentService ) { super(); - this._configurationFileService = configurationFileService; + this._fileService = fileService; this._userConfiguration = this._cachedConfiguration = new CachedRemoteUserConfiguration(remoteAuthority, configurationCache); remoteAgentService.getEnvironment().then(async environment => { if (environment) { - const userConfiguration = this._register(new FileServiceBasedRemoteUserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._configurationFileService)); + const userConfiguration = this._register(new FileServiceBasedRemoteUserConfiguration(environment.settingsPath, REMOTE_MACHINE_SCOPES, this._fileService)); this._register(userConfiguration.onDidChangeConfiguration(configurationModel => this.onDidUserConfigurationChange(configurationModel))); this._userConfigurationInitializationPromise = userConfiguration.initialize(); const configurationModel = await this._userConfigurationInitializationPromise; @@ -142,12 +156,12 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { constructor( private readonly configurationResource: URI, private readonly scopes: ConfigurationScope[] | undefined, - private readonly configurationFileService: ConfigurationFileService + private readonly fileService: IFileService ) { super(); this.parser = new ConfigurationModelParser(this.configurationResource.toString(), this.scopes); - this._register(configurationFileService.onFileChanges(e => this.handleFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this.reload().then(configurationModel => this._onDidChangeConfiguration.fire(configurationModel)), 50)); this._register(toDisposable(() => { this.stopWatchingResource(); @@ -156,7 +170,7 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { } private watchResource(): void { - this.fileWatcherDisposable = this.configurationFileService.watch(this.configurationResource); + this.fileWatcherDisposable = this.fileService.watch(this.configurationResource); } private stopWatchingResource(): void { @@ -166,7 +180,7 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { private watchDirectory(): void { const directory = resources.dirname(this.configurationResource); - this.directoryWatcherDisposable = this.configurationFileService.watch(directory); + this.directoryWatcherDisposable = this.fileService.watch(directory); } private stopWatchingDirectory(): void { @@ -175,15 +189,15 @@ class FileServiceBasedRemoteUserConfiguration extends Disposable { } async initialize(): Promise { - const exists = await this.configurationFileService.exists(this.configurationResource); + const exists = await this.fileService.exists(this.configurationResource); this.onResourceExists(exists); return this.reload(); } async reload(): Promise { try { - const content = await this.configurationFileService.readFile(this.configurationResource); - this.parser.parseContent(content); + const content = await this.fileService.readFile(this.configurationResource); + this.parser.parseContent(content.value.toString()); return this.parser.configurationModel; } catch (e) { return new ConfigurationModel(); @@ -279,7 +293,7 @@ class CachedRemoteUserConfiguration extends Disposable { export class WorkspaceConfiguration extends Disposable { - private readonly _configurationFileService: ConfigurationFileService; + private readonly _fileService: IFileService; private readonly _cachedConfiguration: CachedWorkspaceConfiguration; private _workspaceConfiguration: IWorkspaceConfiguration; private _workspaceConfigurationChangeDisposable: IDisposable = Disposable.None; @@ -293,10 +307,10 @@ export class WorkspaceConfiguration extends Disposable { constructor( configurationCache: IConfigurationCache, - configurationFileService: ConfigurationFileService + fileService: IFileService ) { super(); - this._configurationFileService = configurationFileService; + this._fileService = fileService; this._workspaceConfiguration = this._cachedConfiguration = new CachedWorkspaceConfiguration(configurationCache); } @@ -304,7 +318,7 @@ export class WorkspaceConfiguration extends Disposable { this._workspaceIdentifier = workspaceIdentifier; if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { if (this._workspaceIdentifier.configPath.scheme === Schemas.file) { - this.switch(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + this.switch(new FileServiceBasedWorkspaceConfiguration(this._fileService)); } else { this.waitAndSwitch(this._workspaceIdentifier); } @@ -339,9 +353,9 @@ export class WorkspaceConfiguration extends Disposable { } private async waitAndSwitch(workspaceIdentifier: IWorkspaceIdentifier): Promise { - await this._configurationFileService.whenProviderRegistered(workspaceIdentifier.configPath.scheme); + await whenProviderRegistered(workspaceIdentifier.configPath.scheme, this._fileService); if (!(this._workspaceConfiguration instanceof FileServiceBasedWorkspaceConfiguration)) { - const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._configurationFileService)); + const fileServiceBasedWorkspaceConfiguration = this._register(new FileServiceBasedWorkspaceConfiguration(this._fileService)); await fileServiceBasedWorkspaceConfiguration.load(workspaceIdentifier); this.switch(fileServiceBasedWorkspaceConfiguration); this._loaded = true; @@ -396,13 +410,13 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(private configurationFileService: ConfigurationFileService) { + constructor(private fileService: IFileService) { super(); this.workspaceConfigurationModelParser = new WorkspaceConfigurationModelParser(''); this.workspaceSettings = new ConfigurationModel(); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); this.reloadConfigurationScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); this.workspaceConfigWatcher = this._register(this.watchWorkspaceConfigurationFile()); } @@ -420,9 +434,10 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } let contents = ''; try { - contents = await this.configurationFileService.readFile(this._workspaceIdentifier.configPath); + const content = await this.fileService.readFile(this._workspaceIdentifier.configPath); + contents = content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(this._workspaceIdentifier.configPath); + const exists = await this.fileService.exists(this._workspaceIdentifier.configPath); if (exists) { errors.onUnexpectedError(error); } @@ -454,7 +469,7 @@ class FileServiceBasedWorkspaceConfiguration extends Disposable implements IWork } private watchWorkspaceConfigurationFile(): IDisposable { - return this._workspaceIdentifier ? this.configurationFileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; + return this._workspaceIdentifier ? this.fileService.watch(this._workspaceIdentifier.configPath) : Disposable.None; } private handleWorkspaceFileEvents(event: FileChangesEvent): void { @@ -557,7 +572,7 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC protected readonly _onDidChange: Emitter = this._register(new Emitter()); readonly onDidChange: Event = this._onDidChange.event; - constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private configurationFileService: ConfigurationFileService) { + constructor(protected readonly configurationFolder: URI, workbenchState: WorkbenchState, private fileService: IFileService) { super(); this.configurationNames = [FOLDER_SETTINGS_NAME /*First one should be settings */, TASKS_CONFIGURATION_KEY, LAUNCH_CONFIGURATION_KEY]; @@ -567,15 +582,16 @@ class FileServiceBasedFolderConfiguration extends Disposable implements IFolderC this._cache = new ConfigurationModel(); this.changeEventTriggerScheduler = this._register(new RunOnceScheduler(() => this._onDidChange.fire(), 50)); - this._register(configurationFileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); + this._register(fileService.onFileChanges(e => this.handleWorkspaceFileEvents(e))); } async loadConfiguration(): Promise { const configurationContents = await Promise.all(this.configurationResources.map(async resource => { try { - return await this.configurationFileService.readFile(resource); + const content = await this.fileService.readFile(resource); + return content.value.toString(); } catch (error) { - const exists = await this.configurationFileService.exists(resource); + const exists = await this.fileService.exists(resource); if (exists) { errors.onUnexpectedError(error); } @@ -724,7 +740,7 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat readonly workspaceFolder: IWorkspaceFolder, configFolderRelativePath: string, private readonly workbenchState: WorkbenchState, - configurationFileService: ConfigurationFileService, + fileService: IFileService, configurationCache: IConfigurationCache ) { super(); @@ -732,13 +748,13 @@ export class FolderConfiguration extends Disposable implements IFolderConfigurat this.configurationFolder = resources.joinPath(workspaceFolder.uri, configFolderRelativePath); this.folderConfiguration = this.cachedFolderConfiguration = new CachedFolderConfiguration(workspaceFolder.uri, configFolderRelativePath, configurationCache); if (workspaceFolder.uri.scheme === Schemas.file) { - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); } else { - configurationFileService.whenProviderRegistered(workspaceFolder.uri.scheme) + whenProviderRegistered(workspaceFolder.uri.scheme, fileService) .then(() => { this.folderConfiguration.dispose(); this.folderConfigurationDisposable.dispose(); - this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, configurationFileService); + this.folderConfiguration = new FileServiceBasedFolderConfiguration(this.configurationFolder, this.workbenchState, fileService); this._register(this.folderConfiguration.onDidChange(e => this.onDidFolderConfigurationChange())); this.onDidFolderConfigurationChange(); }); diff --git a/src/vs/workbench/services/configuration/browser/configurationService.ts b/src/vs/workbench/services/configuration/browser/configurationService.ts index 0d898eee98..2a01110a82 100644 --- a/src/vs/workbench/services/configuration/browser/configurationService.ts +++ b/src/vs/workbench/services/configuration/browser/configurationService.ts @@ -14,7 +14,7 @@ import { IWorkspaceContextService, Workspace, WorkbenchState, IWorkspaceFolder, import { ConfigurationChangeEvent, ConfigurationModel, DefaultConfigurationModel } from 'vs/platform/configuration/common/configurationModels'; import { IConfigurationChangeEvent, ConfigurationTarget, IConfigurationOverrides, keyFromOverrideIdentifier, isConfigurationOverrides, IConfigurationData, IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { Configuration, WorkspaceConfigurationChangeEvent, AllKeysConfigurationChangeEvent } from 'vs/workbench/services/configuration/common/configurationModels'; -import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES, ConfigurationFileService } from 'vs/workbench/services/configuration/common/configuration'; +import { FOLDER_CONFIG_FOLDER_NAME, defaultSettingsSchemaId, userSettingsSchemaId, workspaceSettingsSchemaId, folderSettingsSchemaId, IConfigurationCache, machineSettingsSchemaId, LOCAL_MACHINE_SCOPES } from 'vs/workbench/services/configuration/common/configuration'; import { Registry } from 'vs/platform/registry/common/platform'; import { IConfigurationRegistry, Extensions, allSettings, windowSettings, resourceSettings, applicationSettings, machineSettings } from 'vs/platform/configuration/common/configurationRegistry'; import { IWorkspaceIdentifier, isWorkspaceIdentifier, IStoredWorkspaceFolder, isStoredWorkspaceFolder, IWorkspaceFolderCreationData, ISingleFolderWorkspaceIdentifier, isSingleFolderWorkspaceIdentifier, IWorkspaceInitializationPayload, isSingleFolderWorkspaceInitializationPayload, ISingleFolderWorkspaceInitializationPayload, IEmptyWorkspaceInitializationPayload, useSlashForPath, getStoredWorkspaceFolder } from 'vs/platform/workspaces/common/workspaces'; @@ -45,7 +45,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic private cachedFolderConfigs: ResourceMap; private workspaceEditingQueue: Queue; - private readonly configurationFileService: ConfigurationFileService; + private readonly fileService: IFileService; protected readonly _onDidChangeConfiguration: Emitter = this._register(new Emitter()); public readonly onDidChangeConfiguration: Event = this._onDidChangeConfiguration.event; @@ -76,16 +76,16 @@ export class WorkspaceService extends Disposable implements IConfigurationServic this.completeWorkspaceBarrier = new Barrier(); this.defaultConfiguration = new DefaultConfigurationModel(); this.configurationCache = configurationCache; - this.configurationFileService = new ConfigurationFileService(fileService); + this.fileService = fileService; this._configuration = new Configuration(this.defaultConfiguration, new ConfigurationModel(), new ConfigurationModel(), new ConfigurationModel(), new ResourceMap(), new ConfigurationModel(), new ResourceMap(), this.workspace); this.cachedFolderConfigs = new ResourceMap(); this.localUserConfiguration = this._register(new UserConfiguration(environmentService.settingsResource, remoteAuthority ? LOCAL_MACHINE_SCOPES : undefined, fileService)); this._register(this.localUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onLocalUserConfigurationChanged(userConfiguration))); if (remoteAuthority) { - this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, this.configurationFileService, remoteAgentService)); + this.remoteUserConfiguration = this._register(new RemoteUserConfiguration(remoteAuthority, configurationCache, fileService, remoteAgentService)); this._register(this.remoteUserConfiguration.onDidChangeConfiguration(userConfiguration => this.onRemoteUserConfigurationChanged(userConfiguration))); } - this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, this.configurationFileService)); + this.workspaceConfiguration = this._register(new WorkspaceConfiguration(configurationCache, fileService)); this._register(this.workspaceConfiguration.onDidUpdateConfiguration(() => { this.onWorkspaceConfigurationChanged(); if (this.workspaceConfiguration.loaded) { @@ -610,7 +610,7 @@ export class WorkspaceService extends Disposable implements IConfigurationServic return Promise.all([...folders.map(folder => { let folderConfiguration = this.cachedFolderConfigs.get(folder.uri); if (!folderConfiguration) { - folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.configurationFileService, this.configurationCache); + folderConfiguration = new FolderConfiguration(folder, FOLDER_CONFIG_FOLDER_NAME, this.getWorkbenchState(), this.fileService, this.configurationCache); this._register(folderConfiguration.onDidChange(() => this.onWorkspaceFolderConfigurationChanged(folder))); this.cachedFolderConfigs.set(folder.uri, this._register(folderConfiguration)); } diff --git a/src/vs/workbench/services/configuration/common/configuration.ts b/src/vs/workbench/services/configuration/common/configuration.ts index ece67feab0..87c3e15e4d 100644 --- a/src/vs/workbench/services/configuration/common/configuration.ts +++ b/src/vs/workbench/services/configuration/common/configuration.ts @@ -3,9 +3,6 @@ * Licensed under the Source EULA. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { URI } from 'vs/base/common/uri'; -import { IDisposable } from 'vs/base/common/lifecycle'; -import { IFileService } from 'vs/platform/files/common/files'; import { ConfigurationScope } from 'vs/platform/configuration/common/configurationRegistry'; export const FOLDER_CONFIG_FOLDER_NAME = '.azuredatastudio'; @@ -39,38 +36,4 @@ export interface IConfigurationCache { write(key: ConfigurationKey, content: string): Promise; remove(key: ConfigurationKey): Promise; -} - -export class ConfigurationFileService { - - constructor(private readonly fileService: IFileService) { } - - get onFileChanges() { return this.fileService.onFileChanges; } - - whenProviderRegistered(scheme: string): Promise { - if (this.fileService.canHandleResource(URI.from({ scheme }))) { - return Promise.resolve(); - } - return new Promise((c, e) => { - const disposable = this.fileService.onDidChangeFileSystemProviderRegistrations(e => { - if (e.scheme === scheme && e.added) { - disposable.dispose(); - c(); - } - }); - }); - } - - watch(resource: URI): IDisposable { - return this.fileService.watch(resource); - } - - exists(resource: URI): Promise { - return this.fileService.exists(resource); - } - - readFile(resource: URI): Promise { - return this.fileService.readFile(resource).then(content => content.value.toString()); - } - -} +} \ No newline at end of file diff --git a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts index 7da69f1ed6..c853520074 100644 --- a/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts +++ b/src/vs/workbench/services/configurationResolver/browser/configurationResolverService.ts @@ -227,6 +227,10 @@ export abstract class BaseConfigurationResolverService extends AbstractVariableR */ private showUserInput(variable: string, inputInfos: ConfiguredInput[]): Promise { + if (!inputInfos) { + return Promise.reject(new Error(nls.localize('inputVariable.noInputSection', "Variable '{0}' must be defined in an '{1}' section of the debug or task configuration.", variable, 'input'))); + } + // find info for the given input variable const info = inputInfos.filter(item => item.id === variable).pop(); if (info) { @@ -307,4 +311,4 @@ export class ConfigurationResolverService extends BaseConfigurationResolverServi } } -registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); \ No newline at end of file +registerSingleton(IConfigurationResolverService, ConfigurationResolverService, true); diff --git a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts index 54a1712549..f568819053 100644 --- a/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts +++ b/src/vs/workbench/services/configurationResolver/test/electron-browser/configurationResolverService.test.ts @@ -523,6 +523,7 @@ class MockCommandService implements ICommandService { public callCount = 0; onWillExecuteCommand = () => Disposable.None; + onDidExecuteCommand = () => Disposable.None; public executeCommand(commandId: string, ...args: any[]): Promise { this.callCount++; diff --git a/src/vs/workbench/services/editor/common/editorGroupsService.ts b/src/vs/workbench/services/editor/common/editorGroupsService.ts index 13e7407833..1534c8de13 100644 --- a/src/vs/workbench/services/editor/common/editorGroupsService.ts +++ b/src/vs/workbench/services/editor/common/editorGroupsService.ts @@ -179,7 +179,7 @@ export interface IEditorGroupsService { /** * The size of the editor groups area. */ - readonly dimension: IDimension; + readonly contentDimension: IDimension; /** * An active group is the default location for new editors to open. diff --git a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts index 1472122f4d..1ec22693e1 100644 --- a/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts +++ b/src/vs/workbench/services/extensionManagement/common/extensionManagementService.ts @@ -130,7 +130,11 @@ export class ExtensionManagementService extends Disposable implements IExtension } zip(extension: ILocalExtension): Promise { - throw new Error('Not Supported'); + const server = this.getServer(extension); + if (server) { + return server.extensionManagementService.zip(extension); + } + return Promise.reject(`Invalid location ${extension.location.toString()}`); } unzip(zipLocation: URI, type: ExtensionType): Promise { diff --git a/src/vs/workbench/services/extensions/browser/extensionService.ts b/src/vs/workbench/services/extensions/browser/extensionService.ts index bfe24dcb4a..6ddf186f63 100644 --- a/src/vs/workbench/services/extensions/browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/browser/extensionService.ts @@ -14,7 +14,6 @@ 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'; @@ -63,7 +62,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const result: ExtensionHostProcessManager[] = []; const remoteAgentConnection = this._remoteAgentService.getConnection()!; - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), browserWebSocketFactory); + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); result.push(remoteExtHostProcessManager); diff --git a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts index e4cee39752..929c2fa347 100644 --- a/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts +++ b/src/vs/workbench/services/extensions/common/inactiveExtensionUrlHandler.ts @@ -7,6 +7,7 @@ import { localize } from 'vs/nls'; import { Action } from 'vs/base/common/actions'; import { IDisposable, toDisposable, combinedDisposable } from 'vs/base/common/lifecycle'; import { URI } from 'vs/base/common/uri'; +import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IDialogService } from 'vs/platform/dialogs/common/dialogs'; import { IExtensionGalleryService, IExtensionIdentifier, IExtensionManagementService } from 'vs/platform/extensionManagement/common/extensionManagement'; import { IExtensionEnablementService, EnablementState } from 'vs/workbench/services/extensionManagement/common/extensionManagement'; @@ -23,6 +24,8 @@ import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; const FIVE_MINUTES = 5 * 60 * 1000; const THIRTY_SECONDS = 30 * 1000; const URL_TO_HANDLE = 'extensionUrlHandler.urlToHandle'; +const CONFIRMED_EXTENSIONS_CONFIGURATION_KEY = 'extensions.confirmedUriHandlerExtensionIds'; +const CONFIRMED_EXTENSIONS_STORAGE_KEY = 'extensionUrlHandler.confirmedExtensions'; function isExtensionId(value: string): boolean { return /^[a-z0-9][a-z0-9\-]*\.[a-z0-9][a-z0-9\-]*$/i.test(value); @@ -62,7 +65,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { @IExtensionEnablementService private readonly extensionEnablementService: IExtensionEnablementService, @IWindowService private readonly windowService: IWindowService, @IExtensionGalleryService private readonly galleryService: IExtensionGalleryService, - @IStorageService private readonly storageService: IStorageService + @IStorageService private readonly storageService: IStorageService, + @IConfigurationService private readonly configurationService: IConfigurationService + ) { const interval = setInterval(() => this.garbageCollect(), THIRTY_SECONDS); const urlToHandleValue = this.storageService.get(URL_TO_HANDLE, StorageScope.WORKSPACE); @@ -91,6 +96,11 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { return true; } + if (!confirmed) { + const confirmedExtensionIds = this.getConfirmedExtensionIds(); + confirmed = confirmedExtensionIds.has(ExtensionIdentifier.toKey(extensionId)); + } + if (!confirmed) { let uriString = uri.toString(); @@ -100,6 +110,9 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { const result = await this.dialogService.confirm({ message: localize('confirmUrl', "Allow an extension to open this URL?", extensionId), + checkbox: { + label: localize('rememberConfirmUrl', "Don't ask again for this extension."), + }, detail: `${extension.displayName || extension.name} (${extensionId}) wants to open a URL:\n\n${uriString}`, primaryButton: localize('open', "&&Open"), type: 'question' @@ -108,6 +121,10 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { if (!result.confirmed) { return true; } + + if (result.checkboxChecked) { + this.addConfirmedExtensionIdToStorage(extensionId); + } } const handler = this.extensionHandlers.get(ExtensionIdentifier.toKey(extensionId)); @@ -267,6 +284,47 @@ export class ExtensionUrlHandler implements IExtensionUrlHandler, IURLHandler { this.uriBuffer = uriBuffer; } + private getConfirmedExtensionIds(): Set { + const ids = [ + ...this.getConfirmedExtensionIdsFromStorage(), + ...this.getConfirmedExtensionIdsFromConfiguration(), + ].map(extensionId => ExtensionIdentifier.toKey(extensionId)); + + return new Set(ids); + } + + private getConfirmedExtensionIdsFromConfiguration(): Array { + const confirmedExtensionIds = this.configurationService.getValue>(CONFIRMED_EXTENSIONS_CONFIGURATION_KEY); + + if (!Array.isArray(confirmedExtensionIds)) { + return []; + } + + return confirmedExtensionIds; + } + + private getConfirmedExtensionIdsFromStorage(): Array { + const confirmedExtensionIdsJson = this.storageService.get(CONFIRMED_EXTENSIONS_STORAGE_KEY, StorageScope.GLOBAL, '[]'); + + try { + return JSON.parse(confirmedExtensionIdsJson); + } catch (err) { + return []; + } + } + + private addConfirmedExtensionIdToStorage(extensionId: string): void { + const existingConfirmedExtensionIds = this.getConfirmedExtensionIdsFromStorage(); + this.storageService.store( + CONFIRMED_EXTENSIONS_STORAGE_KEY, + JSON.stringify([ + ...existingConfirmedExtensionIds, + ExtensionIdentifier.toKey(extensionId), + ]), + StorageScope.GLOBAL, + ); + } + dispose(): void { this.disposable.dispose(); this.extensionHandlers.clear(); diff --git a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts index f4f7afe4e8..cfe06f03be 100644 --- a/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts +++ b/src/vs/workbench/services/extensions/common/remoteExtensionHostClient.ts @@ -8,7 +8,7 @@ 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 { connectRemoteAgentExtensionHost, IRemoteExtensionHostStartParams, IConnectionOptions, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { IInitData } from 'vs/workbench/api/common/extHost.protocol'; @@ -47,7 +47,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH constructor( private readonly _allExtensions: Promise, private readonly _initDataProvider: IInitDataProvider, - private readonly _webSocketFactory: IWebSocketFactory, + private readonly _socketFactory: ISocketFactory, @IWorkspaceContextService private readonly _contextService: IWorkspaceContextService, @IEnvironmentService private readonly _environmentService: IEnvironmentService, @ITelemetryService private readonly _telemetryService: ITelemetryService, @@ -73,7 +73,7 @@ export class RemoteExtensionHostClient extends Disposable implements IExtensionH const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, commit: this._productService.commit, - webSocketFactory: this._webSocketFactory, + socketFactory: this._socketFactory, addressProvider: { getAddress: async () => { const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(this._initDataProvider.remoteAuthority); diff --git a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts index 68ed608a32..801c3f802f 100644 --- a/src/vs/workbench/services/extensions/electron-browser/extensionService.ts +++ b/src/vs/workbench/services/extensions/electron-browser/extensionService.ts @@ -7,7 +7,6 @@ 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'; @@ -203,6 +202,8 @@ export class ExtensionService extends AbstractExtensionService implements IExten // Update the local registry const result = this._registry.deltaExtensions(toAdd, toRemove.map(e => e.identifier)); + this._onDidChangeExtensions.fire(undefined); + toRemove = toRemove.concat(result.removedDueToLooping); 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(', '))); @@ -219,8 +220,6 @@ export class ExtensionService extends AbstractExtensionService implements IExten await this._extensionHostProcessManagers[0].deltaExtensions(toAdd, toRemove.map(e => e.identifier)); } - this._onDidChangeExtensions.fire(undefined); - for (let i = 0; i < toAdd.length; i++) { this._activateAddedExtensionIfNeeded(toAdd[i]); } @@ -361,7 +360,7 @@ export class ExtensionService extends AbstractExtensionService implements IExten const remoteAgentConnection = this._remoteAgentService.getConnection(); if (remoteAgentConnection) { - const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), nodeWebSocketFactory); + const remoteExtHostProcessWorker = this._instantiationService.createInstance(RemoteExtensionHostClient, this.getExtensions(), this._createProvider(remoteAgentConnection.remoteAuthority), this._remoteAgentService.socketFactory); const remoteExtHostProcessManager = this._instantiationService.createInstance(ExtensionHostProcessManager, false, remoteExtHostProcessWorker, remoteAgentConnection.remoteAuthority, initialActivationEvents); result.push(remoteExtHostProcessManager); } diff --git a/src/vs/workbench/services/keybinding/browser/keybindingService.ts b/src/vs/workbench/services/keybinding/browser/keybindingService.ts index fdcb63e9e7..925a6a6537 100644 --- a/src/vs/workbench/services/keybinding/browser/keybindingService.ts +++ b/src/vs/workbench/services/keybinding/browser/keybindingService.ts @@ -300,7 +300,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveKeybindingItems(items: IKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const keybinding = item.keybinding; if (!keybinding) { // This might be a removal keybinding item in user settings => accept it @@ -323,7 +323,7 @@ export class WorkbenchKeybindingService extends AbstractKeybindingService { private _resolveUserKeybindingItems(items: IUserKeybindingItem[], isDefault: boolean): ResolvedKeybindingItem[] { let result: ResolvedKeybindingItem[] = [], resultLen = 0; for (const item of items) { - const when = (item.when ? item.when.normalize() : undefined); + const when = item.when || undefined; const parts = item.parts; if (parts.length === 0) { // This might be a removal keybinding item in user settings => accept it diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 254c10a6ac..0b9daa5dcd 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -8,6 +8,7 @@ import { Event } from 'vs/base/common/event'; import { MenuBarVisibility } from 'vs/platform/windows/common/windows'; import { ILayoutService } from 'vs/platform/layout/browser/layoutService'; import { Part } from 'vs/workbench/browser/part'; +import { Dimension } from 'vs/base/browser/dom'; export const IWorkbenchLayoutService = createDecorator('layoutService'); @@ -81,6 +82,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ isVisible(part: Parts): boolean; + /** + * Returns if the part is visible. + */ + getDimension(part: Parts): Dimension; + /** * Set activity bar hidden or not */ diff --git a/src/vs/workbench/services/preferences/browser/preferencesService.ts b/src/vs/workbench/services/preferences/browser/preferencesService.ts index 222c593f1a..c9d92d39dc 100644 --- a/src/vs/workbench/services/preferences/browser/preferencesService.ts +++ b/src/vs/workbench/services/preferences/browser/preferencesService.ts @@ -91,11 +91,15 @@ export class PreferencesService extends Disposable implements IPreferencesServic private readonly defaultSettingsRawResource = URI.from({ scheme: network.Schemas.vscode, authority: 'defaultsettings', path: '/defaultSettings.json' }); get userSettingsResource(): URI { - return this.getEditableSettingsURI(ConfigurationTarget.USER)!; + return this.environmentService.settingsResource; } get workspaceSettingsResource(): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { + return null; + } + const workspace = this.contextService.getWorkspace(); + return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); } get settingsEditor2Input(): SettingsEditor2Input { @@ -103,7 +107,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic } getFolderSettingsResource(resource: URI): URI | null { - return this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, resource); + const folder = this.contextService.getWorkspaceFolder(resource); + return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; } resolveModel(uri: URI): Promise { @@ -153,7 +158,7 @@ export class PreferencesService extends Disposable implements IPreferencesServic return Promise.resolve(null); } - createPreferencesEditorModel(uri: URI): Promise> { + async createPreferencesEditorModel(uri: URI): Promise | null> { if (this.isDefaultSettingsResource(uri)) { return this.createDefaultSettingsEditorModel(uri); } @@ -162,16 +167,25 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_LOCAL, uri); } - const workspaceSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); + const workspaceSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE); if (workspaceSettingsUri && workspaceSettingsUri.toString() === uri.toString()) { return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE, workspaceSettingsUri); } if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) { - return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + const settingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, uri); + if (settingsUri && settingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.WORKSPACE_FOLDER, uri); + } } - return Promise.reject(`unknown resource: ${uri.toString()}`); + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + const remoteSettingsUri = remoteEnvironment ? remoteEnvironment.settingsPath : null; + if (remoteSettingsUri && remoteSettingsUri.toString() === uri.toString()) { + return this.createEditableSettingsEditorModel(ConfigurationTarget.USER_REMOTE, uri); + } + + return null; } openRawDefaultSettings(): Promise { @@ -237,11 +251,11 @@ export class PreferencesService extends Disposable implements IPreferencesServic this.openOrSwitchSettings2(ConfigurationTarget.WORKSPACE, undefined, options, group); } - openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { + async openFolderSettings(folder: URI, jsonEditor?: boolean, options?: ISettingsEditorOptions, group?: IEditorGroup): Promise { jsonEditor = typeof jsonEditor === 'undefined' ? this.configurationService.getValue('workbench.settings.editor') === 'json' : jsonEditor; - const folderSettingsUri = this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); + const folderSettingsUri = await this.getEditableSettingsURI(ConfigurationTarget.WORKSPACE_FOLDER, folder); if (jsonEditor) { if (folderSettingsUri) { return this.openOrSwitchSettings(ConfigurationTarget.WORKSPACE_FOLDER, folderSettingsUri, options, group); @@ -389,8 +403,8 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this.editorService.openEditor(input, SettingsEditorOptions.create(settingsOptions), group); } - private doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { - const settingsURI = this.getEditableSettingsURI(target, resource); + private async doSwitchSettings(target: ConfigurationTarget, resource: URI, input: PreferencesEditorInput, group: IEditorGroup, options?: ISettingsEditorOptions): Promise { + const settingsURI = await this.getEditableSettingsURI(target, resource); if (!settingsURI) { return Promise.reject(`Invalid settings URI - ${resource.toString()}`); } @@ -477,18 +491,14 @@ export class PreferencesService extends Disposable implements IPreferencesServic .then(() => this.editorService.createInput({ resource })); } - private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, resource: URI): Promise { - const settingsUri = this.getEditableSettingsURI(configurationTarget, resource); - if (settingsUri) { - const workspace = this.contextService.getWorkspace(); - if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { - return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); - } + private createEditableSettingsEditorModel(configurationTarget: ConfigurationTarget, settingsUri: URI): Promise { + const workspace = this.contextService.getWorkspace(); + if (workspace.configuration && workspace.configuration.toString() === settingsUri.toString()) { return this.textModelResolverService.createModelReference(settingsUri) - .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); + .then(reference => this.instantiationService.createInstance(WorkspaceConfigurationEditorModel, reference, configurationTarget)); } - return Promise.reject(`unknown target: ${configurationTarget} and resource: ${resource.toString()}`); + return this.textModelResolverService.createModelReference(settingsUri) + .then(reference => this.instantiationService.createInstance(SettingsEditorModel, reference, configurationTarget)); } private createDefaultSettingsEditorModel(defaultSettingsUri: URI): Promise { @@ -518,23 +528,19 @@ export class PreferencesService extends Disposable implements IPreferencesServic return this._defaultUserSettingsContentModel; } - private getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): URI | null { + private async getEditableSettingsURI(configurationTarget: ConfigurationTarget, resource?: URI): Promise { switch (configurationTarget) { case ConfigurationTarget.USER: case ConfigurationTarget.USER_LOCAL: - return this.environmentService.settingsResource; + return this.userSettingsResource; case ConfigurationTarget.USER_REMOTE: - return this.environmentService.settingsResource; + const remoteEnvironment = await this.remoteAgentService.getEnvironment(); + return remoteEnvironment ? remoteEnvironment.settingsPath : null; case ConfigurationTarget.WORKSPACE: - if (this.contextService.getWorkbenchState() === WorkbenchState.EMPTY) { - return null; - } - const workspace = this.contextService.getWorkspace(); - return workspace.configuration || workspace.folders[0].toResource(FOLDER_SETTINGS_PATH); + return this.workspaceSettingsResource; case ConfigurationTarget.WORKSPACE_FOLDER: if (resource) { - const folder = this.contextService.getWorkspaceFolder(resource); - return folder ? folder.toResource(FOLDER_SETTINGS_PATH) : null; + return this.getFolderSettingsResource(resource); } } return null; diff --git a/src/vs/workbench/services/preferences/common/preferences.ts b/src/vs/workbench/services/preferences/common/preferences.ts index ce0283bfd7..854188deb9 100644 --- a/src/vs/workbench/services/preferences/common/preferences.ts +++ b/src/vs/workbench/services/preferences/common/preferences.ts @@ -198,7 +198,7 @@ export interface IPreferencesService { getFolderSettingsResource(resource: URI): URI | null; resolveModel(uri: URI): Promise; - createPreferencesEditorModel(uri: URI): Promise>; + createPreferencesEditorModel(uri: URI): Promise | null>; createSettings2EditorModel(): Settings2EditorModel; // TODO openRawDefaultSettings(): Promise; diff --git a/src/vs/workbench/services/preferences/common/preferencesModels.ts b/src/vs/workbench/services/preferences/common/preferencesModels.ts index 25dd38669d..e4cd5ccb77 100644 --- a/src/vs/workbench/services/preferences/common/preferencesModels.ts +++ b/src/vs/workbench/services/preferences/common/preferencesModels.ts @@ -375,6 +375,7 @@ function parse(model: ITextModel, isSettingsProperty: (currentProperty: string, const position = model.getPositionAt(offset); range.endLineNumber = position.lineNumber; range.endColumn = position.column; + settingsPropertyIndex = -1; } }, onArrayBegin: (offset: number, length: number) => { diff --git a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts index 892669d578..1a0724bc96 100644 --- a/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/browser/remoteAgentServiceImpl.ts @@ -4,18 +4,22 @@ *--------------------------------------------------------------------------------------------*/ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; import { IProductService } from 'vs/platform/product/common/product'; -import { browserWebSocketFactory } from 'vs/platform/remote/browser/browserWebSocketFactory'; +import { IWebSocketFactory, BrowserSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; private readonly _connection: IRemoteAgentConnection | null = null; constructor( + webSocketFactory: IWebSocketFactory | null | undefined, @IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService, @IProductService productService: IProductService, @IRemoteAuthorityResolverService remoteAuthorityResolverService: IRemoteAuthorityResolverService, @@ -23,7 +27,8 @@ export class RemoteAgentService extends AbstractRemoteAgentService { ) { super(environmentService); - this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, browserWebSocketFactory, environmentService, remoteAuthorityResolverService, signService)); + this.socketFactory = new BrowserSocketFactory(webSocketFactory); + this._connection = this._register(new RemoteAgentConnection(environmentService.configuration.remoteAuthority!, productService.commit, this.socketFactory, environmentService, remoteAuthorityResolverService, signService)); } getConnection(): IRemoteAgentConnection | null { diff --git a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts index 16faf5df17..33ea5e414f 100644 --- a/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/abstractRemoteAgentService.ts @@ -8,7 +8,7 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { IChannel, IServerChannel, getDelayedChannel } from 'vs/base/parts/ipc/common/ipc'; import { Client } from 'vs/base/parts/ipc/common/ipc.net'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; -import { connectRemoteAgentManagement, IConnectionOptions, IWebSocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { connectRemoteAgentManagement, IConnectionOptions, ISocketFactory, PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService, RemoteAuthorityResolverError } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle'; @@ -21,7 +21,7 @@ import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics import { Emitter } from 'vs/base/common/event'; import { ISignService } from 'vs/platform/sign/common/sign'; -export abstract class AbstractRemoteAgentService extends Disposable implements IRemoteAgentService { +export abstract class AbstractRemoteAgentService extends Disposable { _serviceBrand: any; @@ -83,7 +83,7 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon constructor( remoteAuthority: string, private readonly _commit: string | undefined, - private readonly _webSocketFactory: IWebSocketFactory, + private readonly _socketFactory: ISocketFactory, private readonly _environmentService: IEnvironmentService, private readonly _remoteAuthorityResolverService: IRemoteAuthorityResolverService, private readonly _signService: ISignService @@ -113,7 +113,7 @@ export class RemoteAgentConnection extends Disposable implements IRemoteAgentCon const options: IConnectionOptions = { isBuilt: this._environmentService.isBuilt, commit: this._commit, - webSocketFactory: this._webSocketFactory, + socketFactory: this._socketFactory, addressProvider: { getAddress: async () => { if (firstCall) { diff --git a/src/vs/workbench/services/remote/common/remoteAgentService.ts b/src/vs/workbench/services/remote/common/remoteAgentService.ts index 787366ebdf..12c52aae9e 100644 --- a/src/vs/workbench/services/remote/common/remoteAgentService.ts +++ b/src/vs/workbench/services/remote/common/remoteAgentService.ts @@ -8,7 +8,7 @@ import { RemoteAgentConnectionContext, IRemoteAgentEnvironment } from 'vs/platfo import { IChannel, IServerChannel } from 'vs/base/parts/ipc/common/ipc'; import { IDiagnosticInfoOptions, IDiagnosticInfo } from 'vs/platform/diagnostics/common/diagnosticsService'; import { Event } from 'vs/base/common/event'; -import { PersistenConnectionEvent } from 'vs/platform/remote/common/remoteAgentConnection'; +import { PersistenConnectionEvent as PersistentConnectionEvent, ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; export const RemoteExtensionLogFileName = 'remoteagent'; @@ -17,6 +17,8 @@ export const IRemoteAgentService = createDecorator('remoteA export interface IRemoteAgentService { _serviceBrand: any; + readonly socketFactory: ISocketFactory; + getConnection(): IRemoteAgentConnection | null; getEnvironment(bail?: boolean): Promise; getDiagnosticInfo(options: IDiagnosticInfoOptions): Promise; @@ -27,7 +29,7 @@ export interface IRemoteAgentConnection { readonly remoteAuthority: string; readonly onReconnecting: Event; - readonly onDidStateChange: Event; + readonly onDidStateChange: Event; getChannel(channelName: string): T; registerChannel>(channelName: string, channel: T): void; diff --git a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts index 9f300dda8e..03a94805cc 100644 --- a/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts +++ b/src/vs/workbench/services/remote/electron-browser/remoteAgentServiceImpl.ts @@ -5,14 +5,17 @@ import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IWindowConfiguration } from 'vs/platform/windows/common/windows'; -import { IRemoteAgentConnection } from 'vs/workbench/services/remote/common/remoteAgentService'; +import { IRemoteAgentConnection, IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteAgentService'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import product from 'vs/platform/product/node/product'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { AbstractRemoteAgentService, RemoteAgentConnection } from 'vs/workbench/services/remote/common/abstractRemoteAgentService'; import { ISignService } from 'vs/platform/sign/common/sign'; +import { ISocketFactory } from 'vs/platform/remote/common/remoteAgentConnection'; -export class RemoteAgentService extends AbstractRemoteAgentService { +export class RemoteAgentService extends AbstractRemoteAgentService implements IRemoteAgentService { + + public readonly socketFactory: ISocketFactory; private readonly _connection: IRemoteAgentConnection | null = null; @@ -22,8 +25,9 @@ export class RemoteAgentService extends AbstractRemoteAgentService { @ISignService signService: ISignService ) { super(environmentService); + this.socketFactory = nodeSocketFactory; if (remoteAuthority) { - this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeWebSocketFactory, environmentService, remoteAuthorityResolverService, signService)); + this._connection = this._register(new RemoteAgentConnection(remoteAuthority, product.commit, nodeSocketFactory, environmentService, remoteAuthorityResolverService, signService)); } } diff --git a/src/vs/workbench/services/remote/node/tunnelService.ts b/src/vs/workbench/services/remote/node/tunnelService.ts index 4251b35597..9182754c8c 100644 --- a/src/vs/workbench/services/remote/node/tunnelService.ts +++ b/src/vs/workbench/services/remote/node/tunnelService.ts @@ -12,7 +12,7 @@ import product from 'vs/platform/product/node/product'; import { connectRemoteAgentTunnel, IConnectionOptions } from 'vs/platform/remote/common/remoteAgentConnection'; import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver'; import { ITunnelService, RemoteTunnel } from 'vs/platform/remote/common/tunnel'; -import { nodeWebSocketFactory } from 'vs/platform/remote/node/nodeWebSocketFactory'; +import { nodeSocketFactory } from 'vs/platform/remote/node/nodeSocketFactory'; import { ISignService } from 'vs/platform/sign/common/sign'; export async function createRemoteTunnel(options: IConnectionOptions, tunnelRemotePort: number): Promise { @@ -102,7 +102,7 @@ export class TunnelService implements ITunnelService { const options: IConnectionOptions = { isBuilt: this.environmentService.isBuilt, commit: product.commit, - webSocketFactory: nodeWebSocketFactory, + socketFactory: nodeSocketFactory, addressProvider: { getAddress: async () => { const { authority } = await this.remoteAuthorityResolverService.resolveAuthority(remoteAuthority); diff --git a/src/vs/workbench/services/telemetry/browser/telemetryService.ts b/src/vs/workbench/services/telemetry/browser/telemetryService.ts index 03d1a1d5c0..27c2c51c7e 100644 --- a/src/vs/workbench/services/telemetry/browser/telemetryService.ts +++ b/src/vs/workbench/services/telemetry/browser/telemetryService.ts @@ -104,7 +104,7 @@ export class WebTelemetryAppender implements ITelemetryAppender { this._aiClient.trackEvent('monacoworkbench/' + eventName, data.properties, data.measurements); } - dispose(): Promise | undefined { + flush(): Promise | undefined { if (this._aiClient) { return new Promise(resolve => { this._aiClient!.flush(); diff --git a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts index b926836a32..f9497a042e 100644 --- a/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts +++ b/src/vs/workbench/services/textMate/browser/abstractTextMateService.ts @@ -18,7 +18,8 @@ import { generateTokensCSSForColorMap } from 'vs/editor/common/modes/supports/to 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 { INotificationService, Severity } from 'vs/platform/notification/common/notification'; +import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ExtensionMessageCollector } from 'vs/workbench/services/extensions/common/extensionsRegistry'; import { ITMSyntaxExtensionPoint, grammarsExtPoint } from 'vs/workbench/services/textMate/common/TMGrammars'; import { ITextMateService } from 'vs/workbench/services/textMate/common/textMateService'; @@ -50,7 +51,8 @@ export abstract class AbstractTextMateService extends Disposable implements ITex @IFileService protected readonly _fileService: IFileService, @INotificationService private readonly _notificationService: INotificationService, @ILogService private readonly _logService: ILogService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService ) { super(); this._styleElement = dom.createStyleSheet(); @@ -219,7 +221,7 @@ export abstract class AbstractTextMateService extends Disposable implements ITex this._onDidEncounterLanguage.fire(languageId); } }); - return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService); + return new TMTokenizationSupport(r.languageId, tokenization, this._notificationService, this._configurationService, this._storageService); }, e => { onUnexpectedError(e); return null; @@ -328,6 +330,8 @@ export abstract class AbstractTextMateService extends Disposable implements ITex protected abstract _loadOnigLib(): Promise | undefined; } +const donotAskUpdateKey = 'editor.maxTokenizationLineLength.donotask'; + class TMTokenizationSupport implements ITokenizationSupport { private readonly _languageId: LanguageId; private readonly _actual: TMTokenization; @@ -338,11 +342,12 @@ class TMTokenizationSupport implements ITokenizationSupport { languageId: LanguageId, actual: TMTokenization, @INotificationService private readonly _notificationService: INotificationService, - @IConfigurationService private readonly _configurationService: IConfigurationService + @IConfigurationService private readonly _configurationService: IConfigurationService, + @IStorageService private readonly _storageService: IStorageService ) { this._languageId = languageId; this._actual = actual; - this._tokenizationWarningAlreadyShown = false; + this._tokenizationWarningAlreadyShown = !!(this._storageService.getBoolean(donotAskUpdateKey, StorageScope.GLOBAL)); this._maxTokenizationLineLength = this._configurationService.getValue('editor.maxTokenizationLineLength'); this._configurationService.onDidChangeConfiguration(e => { if (e.affectsConfiguration('editor.maxTokenizationLineLength')) { @@ -368,7 +373,15 @@ class TMTokenizationSupport implements ITokenizationSupport { 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`.")); + this._notificationService.prompt( + Severity.Warning, + 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`."), + [{ + label: nls.localize('neverAgain', "Don't Show Again"), + isSecondary: true, + run: () => this._storageService.store(donotAskUpdateKey, true, StorageScope.GLOBAL) + }] + ); } console.log(`Line (${line.substr(0, 15)}...): longer than ${this._maxTokenizationLineLength} characters, tokenization skipped.`); return nullTokenize2(this._languageId, line, state, offsetDelta); diff --git a/src/vs/workbench/services/textMate/browser/textMateService.ts b/src/vs/workbench/services/textMate/browser/textMateService.ts index b9c475e0eb..ed3864cdef 100644 --- a/src/vs/workbench/services/textMate/browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/browser/textMateService.ts @@ -14,6 +14,7 @@ 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'; +import { IStorageService } from 'vs/platform/storage/common/storage'; export class TextMateService extends AbstractTextMateService { @@ -23,9 +24,10 @@ export class TextMateService extends AbstractTextMateService { @IFileService fileService: IFileService, @INotificationService notificationService: INotificationService, @ILogService logService: ILogService, - @IConfigurationService configurationService: IConfigurationService + @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService); + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); } protected _loadVSCodeTextmate(): Promise { diff --git a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts index db7166180a..cda587a0ac 100644 --- a/src/vs/workbench/services/textMate/electron-browser/textMateService.ts +++ b/src/vs/workbench/services/textMate/electron-browser/textMateService.ts @@ -20,6 +20,7 @@ import { TextMateWorker } from 'vs/workbench/services/textMate/electron-browser/ import { ITextModel } from 'vs/editor/common/model'; import { Disposable } from 'vs/base/common/lifecycle'; import { UriComponents, URI } from 'vs/base/common/uri'; +import { IStorageService } from 'vs/platform/storage/common/storage'; const RUN_TEXTMATE_IN_WORKER = false; @@ -110,9 +111,10 @@ export class TextMateService extends AbstractTextMateService { @INotificationService notificationService: INotificationService, @ILogService logService: ILogService, @IConfigurationService configurationService: IConfigurationService, + @IStorageService storageService: IStorageService, @IModelService private readonly _modelService: IModelService, ) { - super(modeService, themeService, fileService, notificationService, logService, configurationService); + super(modeService, themeService, fileService, notificationService, logService, configurationService, storageService); this._worker = null; this._workerProxy = null; this._tokenizers = Object.create(null); diff --git a/src/vs/workbench/test/browser/part.test.ts b/src/vs/workbench/test/browser/part.test.ts index a80ea38af0..c051ea2112 100644 --- a/src/vs/workbench/test/browser/part.test.ts +++ b/src/vs/workbench/test/browser/part.test.ts @@ -10,7 +10,6 @@ import { TestThemeService } from 'vs/platform/theme/test/common/testThemeService import { append, $, hide } from 'vs/base/browser/dom'; import { TestStorageService, TestLayoutService } from 'vs/workbench/test/workbenchTestServices'; import { StorageScope } from 'vs/platform/storage/common/storage'; -import { Orientation } from 'vs/base/browser/ui/grid/grid'; class SimplePart extends Part { @@ -19,7 +18,7 @@ class SimplePart extends Part { minimumHeight: number; maximumHeight: number; - layout(width: number, height: number, orientation: Orientation): void { + layout(width: number, height: number): void { throw new Error('Method not implemented.'); } @@ -172,4 +171,4 @@ suite('Workbench parts', () => { assert(!document.getElementById('myPart.title')); assert(document.getElementById('myPart.content')); }); -}); \ No newline at end of file +}); 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..40c7ffb554 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostMessagerService.test.ts @@ -26,6 +26,7 @@ const emptyDialogService = new class implements IDialogService { const emptyCommandService: ICommandService = { _serviceBrand: undefined, onWillExecuteCommand: () => ({ dispose: () => { } }), + onDidExecuteCommand: () => ({ dispose: () => { } }), executeCommand: (commandId: string, ...args: any[]): Promise => { return Promise.resolve(undefined); } diff --git a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts index 6a887f089a..b022fcc154 100644 --- a/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/extHostWorkspace.test.ts @@ -573,18 +573,18 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'foo'); - assert.equal(_includeFolder, undefined); - assert.equal(excludePatternOrDisregardExcludes, undefined); + assert.equal(_includeFolder, null); + assert.equal(excludePatternOrDisregardExcludes, null); assert.equal(maxResults, 10); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles('foo', undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles('foo', undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -595,17 +595,17 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); - assert.equal(excludePatternOrDisregardExcludes, undefined); - return Promise.resolve(undefined); + assert.equal(excludePatternOrDisregardExcludes, null); + return Promise.resolve(null); } }); const ws = createExtHostWorkspace(rpcProtocol, { id: 'foo', folders: [aWorkspaceFolderData(URI.file(root), 0)], name: 'Test' }, new NullLogService(), new Counter()); - return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined!, 10, new ExtensionIdentifier('test')).then(() => { + return ws.findFiles(new RelativePattern('/other/folder', 'glob/**'), undefined, 10, new ExtensionIdentifier('test')).then(() => { assert(mainThreadCalled, 'mainThreadCalled'); }); }); @@ -616,12 +616,12 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert.equal(includePattern, 'glob/**'); assert.deepEqual(_includeFolder, URI.file('/other/folder').toJSON()); assert.equal(excludePatternOrDisregardExcludes, false); - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -637,9 +637,9 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; - return Promise.resolve(undefined); + return Promise.resolve(null); } }); @@ -657,10 +657,10 @@ suite('ExtHostWorkspace', function () { let mainThreadCalled = false; rpcProtocol.set(MainContext.MainThreadWorkspace, new class extends mock() { - $startFileSearch(includePattern: string, _includeFolder: UriComponents | undefined, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { + $startFileSearch(includePattern: string, _includeFolder: UriComponents | null, excludePatternOrDisregardExcludes: string | false, maxResults: number, token: CancellationToken): Promise { mainThreadCalled = true; assert(excludePatternOrDisregardExcludes, 'glob/**'); // Note that the base portion is ignored, see #52651 - return Promise.resolve(undefined); + return Promise.resolve(null); } }); diff --git a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts index f9ddf13d57..4a9c405dc7 100644 --- a/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts +++ b/src/vs/workbench/test/electron-browser/api/mainThreadWorkspace.test.ts @@ -39,7 +39,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('foo', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('foo', null, null, 10, new CancellationTokenSource().token); }); test('exclude defaults', () => { @@ -61,7 +61,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, undefined, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, null, 10, new CancellationTokenSource().token); }); test('disregard excludes', () => { @@ -82,7 +82,7 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, false, 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, false, 10, new CancellationTokenSource().token); }); test('exclude string', () => { @@ -96,6 +96,6 @@ suite('MainThreadWorkspace', () => { }); const mtw: MainThreadWorkspace = instantiationService.createInstance(MainThreadWorkspace, SingleProxyRPCProtocol({ $initializeWorkspace: () => { } })); - return mtw.$startFileSearch('', undefined, 'exclude/**', 10, new CancellationTokenSource().token); + return mtw.$startFileSearch('', null, 'exclude/**', 10, new CancellationTokenSource().token); }); }); diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index 56b7d3cc8f..3454f9fb64 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -474,6 +474,10 @@ export class TestLayoutService implements IWorkbenchLayoutService { return true; } + getDimension(_part: Parts): Dimension { + return new Dimension(0, 0); + } + public getContainer(_part: Parts): HTMLElement { return null!; } @@ -667,7 +671,7 @@ export class TestEditorGroupsService implements IEditorGroupsService { whenRestored: Promise = Promise.resolve(undefined); willRestoreEditors = false; - dimension = { width: 800, height: 600 }; + contentDimension = { width: 800, height: 600 }; get activeGroup(): IEditorGroup { return this.groups[0]; diff --git a/src/vs/workbench/workbench.web.api.ts b/src/vs/workbench/workbench.web.api.ts index 71f5499e79..4d66e8e15e 100644 --- a/src/vs/workbench/workbench.web.api.ts +++ b/src/vs/workbench/workbench.web.api.ts @@ -8,6 +8,7 @@ import { main } from 'vs/workbench/browser/web.main'; import { UriComponents } from 'vs/base/common/uri'; import { IFileSystemProvider } from 'vs/platform/files/common/files'; import { IRequestOptions, IRequestContext } from 'vs/platform/request/common/request'; +import { IWebSocketFactory } from 'vs/platform/remote/browser/browserSocketFactory'; export interface IWorkbenchConstructionOptions { @@ -44,6 +45,11 @@ export interface IWorkbenchConstructionOptions { * In case not provided, workbench uses XMLHttpRequest. */ requestHandler?: (requestOptions: IRequestOptions) => Promise; + + /** + * A factory for web sockets. + */ + webSocketFactory?: IWebSocketFactory; } /** diff --git a/test/electron/renderer.html b/test/electron/renderer.html index 1eb67318bf..7245438959 100644 --- a/test/electron/renderer.html +++ b/test/electron/renderer.html @@ -19,4 +19,4 @@ - \ No newline at end of file + diff --git a/test/smoke/package.json b/test/smoke/package.json index 2d92a7a884..11b5662b20 100644 --- a/test/smoke/package.json +++ b/test/smoke/package.json @@ -22,7 +22,7 @@ "@types/webdriverio": "4.6.1", "concurrently": "^3.5.1", "cpx": "^1.5.0", - "electron": "4.2.5", + "electron": "4.2.7", "htmlparser2": "^3.9.2", "mkdirp": "^0.5.1", "mocha": "^5.2.0", diff --git a/test/smoke/yarn.lock b/test/smoke/yarn.lock index 4af77efee7..b86356d3ac 100644 --- a/test/smoke/yarn.lock +++ b/test/smoke/yarn.lock @@ -676,10 +676,10 @@ electron-download@^4.1.0: semver "^5.4.1" sumchecker "^2.0.2" -electron@4.2.5: - version "4.2.5" - resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.5.tgz#1d1432c38e2b2190318f7ca30897cdfdcf942e5a" - integrity sha512-P132MXzTtyn2ZaekhKi5JeHzmTAMuR/uQt4hrg3vfJV7fpncx9SL6UFwHAK1DU13iiyZJqqIziNUu+o8nODHsA== +electron@4.2.7: + version "4.2.7" + resolved "https://registry.yarnpkg.com/electron/-/electron-4.2.7.tgz#bdd2dbf489a4a4255405bd8330cc8509831d29ba" + integrity sha512-Azpkw0OPzKVipSsN9/0DrBQhXOpG48Q1gTG7Akchtv37s8TijMe403TUgHxGGhw2ti117ek51kYf7NXLhjXqoA== dependencies: "@types/node" "^10.12.18" electron-download "^4.1.0" diff --git a/test/tree/public/compressed.json b/test/tree/public/compressed.json new file mode 100644 index 0000000000..c0b5d4d716 --- /dev/null +++ b/test/tree/public/compressed.json @@ -0,0 +1,15620 @@ +[ + { + "element": { + "name": "eclipse.platform.debug" + }, + "children": [ + { + "element": { + "name": ".git" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "branches" + }, + "children": [] + }, + { + "element": { + "name": "config" + }, + "incompressible": true + }, + { + "element": { + "name": "description" + }, + "incompressible": true + }, + { + "element": { + "name": "hooks" + }, + "children": [ + { + "element": { + "name": "applypatch-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "fsmonitor-watchman.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "post-update.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-applypatch.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-commit.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-push.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-rebase.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "pre-receive.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "prepare-commit-msg.sample" + }, + "incompressible": true + }, + { + "element": { + "name": "update.sample" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "index" + }, + "incompressible": true + }, + { + "element": { + "name": "info" + }, + "children": [ + { + "element": { + "name": "exclude" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "logs" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "objects" + }, + "children": [ + { + "element": { + "name": "info" + }, + "children": [] + }, + { + "element": { + "name": "pack" + }, + "children": [ + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.idx" + }, + "incompressible": true + }, + { + "element": { + "name": "pack-2b1503bd0b85396d8596e9e99d956bfc3fbe497b.pack" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "packed-refs" + }, + "incompressible": true + }, + { + "element": { + "name": "refs" + }, + "children": [ + { + "element": { + "name": "heads" + }, + "children": [ + { + "element": { + "name": "master" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "remotes" + }, + "children": [ + { + "element": { + "name": "origin" + }, + "children": [ + { + "element": { + "name": "HEAD" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "tags" + }, + "children": [ + { + "element": { + "name": "I20190722-1800" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "shallow" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": "CONTRIBUTING" + }, + "incompressible": true + }, + { + "element": { + "name": "LICENSE" + }, + "incompressible": true + }, + { + "element": { + "name": "NOTICE" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ExternalToolsCore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "BackgroundResourceRefresher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsCoreUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderCoreUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolBuilder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registry" + }, + "children": [ + { + "element": { + "name": "ExternalToolMigration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMigrationMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.core.variables" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "dynamicVariables.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "valueVariables.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContributedValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EclipseHomeVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "IDynamicVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDynamicVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStringVariableManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueVariableListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "DebugEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugException.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEventSetListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationMigrationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchesListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcessFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPrototypeAttributesLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Launch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnectHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrameHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledStateRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRestartHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResumeHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFiltersHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepIntoHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepReturnHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminateHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "Breakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointImportParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDisconnect.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDropToFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IErrorReportingExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFilteredStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IFlushableStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IIndexedValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILogicalStructureTypeDelegate2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrieval.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockRetrievalExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStep.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStepFilters.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStreamsProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendResume.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITerminate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITriggerPoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueModification.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryByte.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RuntimeProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableSourceLocator2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePathComputerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSourceContainerTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContainerSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalFileStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ZipEntryStorage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "BreakpointImportParticipantDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCoreMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugOptions.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConfigurationElementConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExpressionsListener2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugCoreConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMementoConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationWorkingCopy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchMode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NullStreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OutputStreamMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Preferences.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PreferredDelegateModifyListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshScopeComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFilterManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemVariableResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpression.java" + }, + "incompressible": true + }, + { + "element": { + "name": "XMLMemento.java" + }, + "incompressible": true + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ForEachCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Request.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepFiltersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommand.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "GroupLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupMemberChangeListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "observer" + }, + "children": [ + { + "element": { + "name": "ProcessObserver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamObserver.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLocatorMementoComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourcePathComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "containers" + }, + "children": [ + { + "element": { + "name": "ArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerType.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ContainerResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DateTimeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceResolver.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointImportParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationComparators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchDelegates.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchModes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "logicalStructureTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "processFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerTypes.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceLocators.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcePathComputers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "statusHandlers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stepFilters.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "watchExpressionDelegates.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.core" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "pdavm" + }, + "children": [ + { + "element": { + "name": "PDAVirtualMachine.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "vmtest10.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest2.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest3.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest6.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest8.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest9.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "vmtest_children.pda" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "readme.html" + }, + "incompressible": true + }, + { + "element": { + "name": "samples" + }, + "children": [ + { + "element": { + "name": "counter.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "drop.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "example.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "fibonacci.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "registers.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "stack.pda" + }, + "incompressible": true + }, + { + "element": { + "name": "structures.pda" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "build.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ClockControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LengthControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoControl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeControl.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugCorePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDALineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineBreakpoint.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchpoint.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "IPDAEventListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArray.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAArrayEntry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordStructureDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "protocol" + }, + "children": [ + { + "element": { + "name": "PDABitFieldData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAChildrenCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAClearBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDACommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADropFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvalResultEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEventStopCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAExitedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAFrameData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAGroupsCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAListResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDANoSuchLabelEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPopDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAPushDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegisterData.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARegistersEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunControlEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetBreakpointCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetDataCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASetVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStackDepthCommandResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAStepReturnCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminateCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAUnimplementedInstructionEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumeCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMResumedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMStartedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMSuspendedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVMTerminatedEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVarCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAWatchCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "PDASourceLookupDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceLookupParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourcePathComputerDelegate.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "src_ant" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ant" + }, + "children": [ + { + "element": { + "name": "tasks" + }, + "children": [ + { + "element": { + "name": "PreProcessor.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.memory" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "hex_tree.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "launch.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_segment.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_unit.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "MemoryViewSamplePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "core" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleDebugTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegister.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleRegisterGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleStackFrame.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleThread.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "engine" + }, + "children": [ + { + "element": { + "name": "SampleEngine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleMemoryUnit.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfig" + }, + "children": [ + { + "element": { + "name": "SampleLaunchConfigurationDelegateEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleLaunchTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SampleModelPresentation.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.mixedmode" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "mixedmode" + }, + "children": [ + { + "element": { + "name": "Activator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AntExtraTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearPreferredDelegatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingLaunchConfigurationDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DoNothingMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "messages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.examples.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "OSGI-INF" + }, + "children": [ + { + "element": { + "name": "l10n" + }, + "children": [ + { + "element": { + "name": "bundle.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "pop.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "push.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "clef.png" + }, + "incompressible": true + }, + { + "element": { + "name": "note.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "pda.gif" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "examples" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "midi" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "CheckboxModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlsMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiEventModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiStepOverHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerControlsModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SequencerModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TrackModelProxy.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "detailpanes" + }, + "children": [ + { + "element": { + "name": "ClockSliderDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ControlDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TempoSliderDetailPane.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "ExampleLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiLaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MidiTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pda" + }, + "children": [ + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddPDAMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommandAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDADebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARestartDebugCommand.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAVirtualFindAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "PDABreakpointAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDARunToLineAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAToggleWatchpointsTargetFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "editor" + }, + "children": [ + { + "element": { + "name": "AnnotationHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistProcessor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAContentAssistant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAEditorMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAScanner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDASourceViewerConfiguration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopFrameActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordFinder.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launcher" + }, + "children": [ + { + "element": { + "name": "PDALaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDAMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PDATabGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "presentation" + }, + "children": [ + { + "element": { + "name": "PDAModelPresentation.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "AbstractDataStackViewHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CanPushTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckboxView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DataStackView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PushHandler.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.tests" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Platform Debug Test Suite.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "image1.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "image2.gif" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "tests" + }, + "children": [ + { + "element": { + "name": "AbstractDebugTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AutomatedSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LocalSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceSuite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint" + }, + "children": [ + { + "element": { + "name": "BreakpointOrderingTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocumentAdapterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTestUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MockProcess.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamsProxyTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "ExpressionManagerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launching" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AcceleratorSubstitutionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentParsingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArgumentsPrinter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CancellingLaunchDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileStore.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugFileSystem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchFavoriteTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistoryTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTabTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunchDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "SourceLookupFacilityTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestLaunch.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceDirector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestSourceLocator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStackFrame.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "statushandlers" + }, + "children": [ + { + "element": { + "name": "StatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusHandlerTests.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stepfilters" + }, + "children": [ + { + "element": { + "name": "StepFiltersTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestStepFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "view" + }, + "children": [ + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "DynamicRenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockDynamic.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockOne.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockThree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockTwo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "viewer" + }, + "children": [ + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "AbstractViewerModelTest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColumnPresentationTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransformTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITestModelUpdatesListenerConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerCheckTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerLazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerTopIndexTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "JFaceViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContextTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TestModelUpdatesListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerAutopopulateAgent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreePathWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerContentTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerDeltaTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerFilterTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerLazyModeTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPerformanceTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerPopupTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerSelectionTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerStateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualViewerUpdateTests.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VisibleVirtualItemValidator.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "test-import" + }, + "children": [ + { + "element": { + "name": "Import1.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import2.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import3.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import4.launch" + }, + "incompressible": true + }, + { + "element": { + "name": "Import5.launch" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "test.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "org.eclipse.debug.ui" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".options" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "css" + }, + "children": [ + { + "element": { + "name": "e4-dark_debug_prefstyle.css" + }, + "incompressible": true + }, + { + "element": { + "name": "e4-light_debug_prefstyle.css" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "forceQualifierUpdate.txt" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.gif@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "changevariablevalue_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "changevariablevalue_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "collapseall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copy_edit_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "copyviewtoclipboard_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_compact@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view_tree@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debuglast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "delete_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_auto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_hide@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_right@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under.png" + }, + "incompressible": true + }, + { + "element": { + "name": "det_pane_under@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "disconnect_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb.png" + }, + "incompressible": true + }, + { + "element": { + "name": "display_selected_mb@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group.png" + }, + "incompressible": true + }, + { + "element": { + "name": "dissolve_group@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame.png" + }, + "incompressible": true + }, + { + "element": { + "name": "drop_to_frame@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "enabled_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expandall@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "filter_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout.png" + }, + "incompressible": true + }, + { + "element": { + "name": "hierarchicalLayout@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "link_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryreset_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "metharg_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "monitorexpression_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "next_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prev_thread_nav@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "printview_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prop_ps@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_all_triggers.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk.png" + }, + "incompressible": true + }, + { + "element": { + "name": "removememory_tsk@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "reset_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "restart_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "resume_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runlast_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "runtoline_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_brkp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepbystep_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepinto_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepover_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stepreturn_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "suspend_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced.png" + }, + "incompressible": true + }, + { + "element": { + "name": "synced@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_all_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminate_rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "tnames_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "toggledetailpane_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto.png" + }, + "incompressible": true + }, + { + "element": { + "name": "unlink_proto@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeerr_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "writeout_co@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "debug_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_exc@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart.png" + }, + "incompressible": true + }, + { + "element": { + "name": "term_restart@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watch_exp@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "breakpoint_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoint_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_persp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "details_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "module_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "register_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "variable_view@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "watchlist_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "arraypartition_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "arraypartition_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_grp_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkp_type@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "brkpd_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check.png" + }, + "incompressible": true + }, + { + "element": { + "name": "check@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "common_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugts_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debugtt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "environment_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "envvar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "expression_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "file_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "fldr_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericreggroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericregister_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "genericvariable_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top.png" + }, + "incompressible": true + }, + { + "element": { + "name": "inst_ptr_top@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "jar_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "ldebug_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lgroup_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lrun_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memory_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "memorychanged_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprc_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "osprct_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "persp_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prj_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "proto_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "read_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "readwrite_obj_disabled@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "refresh_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rundebug@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stckframe_running_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "terminatedlaunch_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "thread_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threads_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "threadt_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck.png" + }, + "incompressible": true + }, + { + "element": { + "name": "uncheck@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset.png" + }, + "incompressible": true + }, + { + "element": { + "name": "workset@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled.png" + }, + "incompressible": true + }, + { + "element": { + "name": "write_obj_disabled@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ovr16" + }, + "children": [ + { + "element": { + "name": "error.png" + }, + "incompressible": true + }, + { + "element": { + "name": "error@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype.png" + }, + "incompressible": true + }, + { + "element": { + "name": "prototype@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "skip_breakpoint_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "stcksync_ov@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent.png" + }, + "incompressible": true + }, + { + "element": { + "name": "transparent@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov.png" + }, + "incompressible": true + }, + { + "element": { + "name": "var_cntnt_prvdr_ov@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "adddir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "addsrcloc_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "debug_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "editdir_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "edtsrclkup_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "export_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_brkpts_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "import_config_wizban.png" + }, + "incompressible": true + }, + { + "element": { + "name": "profile_wiz.png" + }, + "incompressible": true + }, + { + "element": { + "name": "run_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "breakpointOrganizers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleColorProviders.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consoleLineTrackers.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "contextViewBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelContextBindings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "debugModelPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "detailPaneFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTabs.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchConfigurationTypeImages.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchGroups.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "launchShortcuts.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "memoryRenderings.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "sourceContainerPresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "stringVariablePresentations.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "toggleBreakpointsTargetFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "variableValueEditors.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "debug" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractDebugCheckboxSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugListSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildBeforeLaunchStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ColorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompositeDebugImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelPropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPerspectiveFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DelegatingModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DynamicInstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchHistoryChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchLabelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerAnnotation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerImageProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InstructionPointerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LazyModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MultipleInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Pair.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceExtender.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SWTFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateToggleValue.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextGetSetEditingSupport.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableValueEditorManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractDebugActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractRemoveAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractSelectionActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "AddToFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConfigureColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecutionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchablePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenDebugConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenProfileConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenRunConfigurations.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetRunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunHistoryMenuAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StatusInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleFilterAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpointGroups" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointsViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AdvancedGroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointGroupMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSelectionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClearDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyBreakpointsActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupBreakpointsByDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveFromWorkingSetAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectBreakpointWorkingsetDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetDefaultBreakpointGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDefaultGroupAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpointSortBy" + }, + "children": [ + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SortBreakpointsByAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "AccessWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsCollapseAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsExpandAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteWorkingsetsMessageDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkBreakpointsWithDebugViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ModificationWatchpointToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModifyWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenBreakpointMarkerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllTriggerPointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetMethodBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetToggleLineBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetWatchpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowSupportedBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTargetBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SkipAllBreakpointsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointObjectActionDelegate.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expressions" + }, + "children": [ + { + "element": { + "name": "AddWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConvertToWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyExpressionsToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressinInPlaceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnableWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasteWatchExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReevaluateWatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllExpressionsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionFactoryTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "ChangeVariableValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChangeVariableValueInputDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectAllVariablesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowTypesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleDetailPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "DetailPaneAssignValueAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneMaxLengthDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneWordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "IBreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OtherBreakpointCategory.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "commands" + }, + "children": [ + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ActionsUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugActionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DisconnectCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DropToFrameCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExecuteActionRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICommandParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IEnabledTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestartCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResumeCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepIntoCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepOverCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StepReturnCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAllActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRelaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleStepFiltersCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateActionsRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpdateHandlerRequest.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "contextlaunching" + }, + "children": [ + { + "element": { + "name": "ContextMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextRunner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingResourceManager.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "DebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextSourceProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModelContextBindingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugWindowContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchSuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SuspendTriggerAdapterFactory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "adapters" + }, + "children": [ + { + "element": { + "name": "AsynchronousDebugLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultBreakpointsViewInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegmentLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Messages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameSourceDisplayAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionCellModifier.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "groups" + }, + "children": [ + { + "element": { + "name": "CommonTabLite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupCycleHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupElementLaunchedHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GroupLaunchHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsupportedModeHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "hover" + }, + "children": [ + { + "element": { + "name": "DebugTextHover.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionInformationControlCreator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "importexport" + }, + "children": [ + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointImportExport.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsPathDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EmbeddedBreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IImportExportConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportExportMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardExportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpoints.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardImportBreakpointsSelectionPage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launchconfigurations" + }, + "children": [ + { + "element": { + "name": "ExportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizard.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportLaunchConfigurationsWizardPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WizardMessages.properties" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ClosedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CollapseAllLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorProjectPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CompileErrorPromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateLaunchConfigurationPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugModePromptStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeleteLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeletedProjectFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DuplicateLaunchDelegatesStatusHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentVariable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterDropDownMenuCreator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterLaunchConfigurationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchCategoryFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationEditDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationFilteredTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationPropertiesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabGroupWrapper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTabImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTreeContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationTypeFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchDelegateNotAvailableHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchGroupFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchHistory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchTabContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OrganizeFavoritesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PerspectiveManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetWithPrototypeValuesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SaveScopeResourcesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectFavoritesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchModesDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLaunchersDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowCommandLineDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnlinkPrototypeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetsFilter.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "IMemoryBlockConnection.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPersistableDebugElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingBindings.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractAsyncTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractAsyncTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPresentationContext.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "elements" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerInputMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegisterGroupMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WatchExpressionEditor.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "preferences" + }, + "children": [ + { + "element": { + "name": "BooleanFieldEditor2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPreferencesMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchConfigurationsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchPerspectivePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchersPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunDebugPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewManagementPreferencePage.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "quickaccess" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchQuickAccessElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProfileQuickAccessComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunQuickAccessComputer.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AddContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicContainerContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditSourceLookupPathAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LookupSourceAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Prompter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResolveDuplicatesHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RestoreDefaultAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupFacility.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupPanel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupUIUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UpAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "browsers" + }, + "children": [ + { + "element": { + "name": "ArchiveFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DirectorySourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalArchiveSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectSourceContainerDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkspaceSourceContainerBrowser.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "FilePrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FolderPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PasswordPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PromptingResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResourceSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedResourceResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectedTextResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringPrompt.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringSubstitutionMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariablePresentationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPropertyArgumentSelector.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "viewers" + }, + "children": [ + { + "element": { + "name": "AbstractUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousSchedulingRuleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FindElementDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelNode.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PartPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableAddRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableEditorImpl.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableInsertRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRemoveRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableReplaceRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breadcrumb" + }, + "children": [ + { + "element": { + "name": "AbstractBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDetails.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbItemDropDown.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreadcrumbDropDownSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeViewerDropDown.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "ChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FilterTransform.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InternalVirtualTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MementoUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SubTreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TimeTriggeredProgressMonitorDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerAdapterService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerStateTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerUpdateMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualFindAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "ICheckUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ICheckboxModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenCountUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentation2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IColumnPresentationFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementCompareRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IElementMementoRequest.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHasChildrenUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelChangedListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelDeltaVisitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxy2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelProxyFactory2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStateUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IStatusMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ITreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewActionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputRequestor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerInputUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IViewerUpdateListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualItemValidator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModelDelta.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeModelViewerFilter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewerInputService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualItem.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTree.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VirtualTreeModelViewer.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "provisional" + }, + "children": [ + { + "element": { + "name": "AbstractColumnPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousContentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAsynchronousLabelAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IChildrenRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContainerRequestMonitor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILabelRequestMonitor.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "update" + }, + "children": [ + { + "element": { + "name": "BreakpointContainerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugTargetProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelProxyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultModelSelectionPolicyFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultSelectionPolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultVariableViewModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultWatchExpressionModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EventHandlerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionManagerModelProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchManagerProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlockProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRetrievalProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StackFrameEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ThreadEventHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewEventHandler.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "views" + }, + "children": [ + { + "element": { + "name": "DebugModelPresentationContext.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUIViewsMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugExceptionHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "breakpoints" + }, + "children": [ + { + "element": { + "name": "BreakpointContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointContainerWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointOrganizerManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointPersistableElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointSetOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetElementAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointWorkingSetPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointsViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ElementComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProjectBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetBreakpointOrganizer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetCategory.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleLineNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveAllTerminatedAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleRemoveLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleShowPreferencesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTerminateAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProcessTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardErrorAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowStandardOutAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowWhenContentChangesAction.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "expression" + }, + "children": [ + { + "element": { + "name": "ExpressionDropAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExpressionView.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "launch" + }, + "children": [ + { + "element": { + "name": "BreadcrumbDropDownAutoExpandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreadcrumbWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementAdapterFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementHelper.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugToolBarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugViewModeAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "Decoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DecorationManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageImageDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewBreadcrumb.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewCopyToClipboardActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StandardDecoration.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TerminateAndRemoveHandler.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CodePagesPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LinkRenderingPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryBlocksTreeViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewIdRegistry.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeModelContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewTreeViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryViewUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MonitorMemoryBlockDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "NewMemoryViewAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PropertyChangeNotifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveMemoryRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RemoveRenderingContextAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingViewPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetMemoryBlockPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RetargetAddMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SetPaddedStringPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SwitchMemoryBlockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SynchronizeInfo.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMemoryMonitorsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleSplitPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleViewPaneAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneOrientationAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneRenderingMgr.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewPaneSelectionProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ViewTabEnablementManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "renderings" + }, + "children": [ + { + "element": { + "name": "ASCIIRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ASCIIRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractBaseTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractVirtualContentTableModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncCopyTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncPrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingUpdatePolicy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncTableRenderingViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AsyncVirtualContentTableViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BasicDebugViewContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BigEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CopyTableRenderingToClipboardAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CreateRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultEndianessAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ErrorRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FormatTableRenderingDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressComposite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "GoToAddressDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexIntegerRenderingDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HexRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IContentChangeComputer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPresentationErrorListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVirtualContentListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LittleEndianAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemorySegment.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PendingPropertyChanges.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrintTableRenderingAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ReformatAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RenderingsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ResetToBaseAddressAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingCellModifier.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentDescriptor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingContentProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLabelProviderEx.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingLine.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingModel.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPrefAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TableRenderingPropertiesPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "UnsignedIntegerRenderingTypeDelegate.java" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "modules" + }, + "children": [ + { + "element": { + "name": "IHelpContextIdProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ModulesViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "registers" + }, + "children": [ + { + "element": { + "name": "RegistersView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RegistersViewMessages.properties" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "AvailableLogicalStructuresAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditVariableLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedValuePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IndexedVariablePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LogicalStructureCache.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SelectionDragAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleLogicalStructureAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleShowColumnsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableViewToggleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "VariablesViewResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "details" + }, + "children": [ + { + "element": { + "name": "AbstractDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AvailableDetailPanesAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DefaultDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DetailPaneProxy.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneContainer2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageDetailPane.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "AbstractBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugPopup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugUITools.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DeferredDebugElementWorkbenchAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EnvironmentTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointOrganizerDelegateExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IBreakpointTypeCategory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugEditorPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugModelPresentationExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugUIConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPane3.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDetailPaneFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInstructionPointerPresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTab2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchConfigurationTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchShortcut2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourcePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IValueDetailListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "InspectPopupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeDecorator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PrototypeTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RefreshTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StringVariableSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingDirectoryBlock.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "AbstractLaunchHistoryAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractLaunchToolbarAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AddMemoryRenderingActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BreakpointTypesContribution.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ContextualLaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugCommandHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryBlocksTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IAddMemoryRenderingsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ILaunchable.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRunToLineTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTarget.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetExtension2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IToggleBreakpointsTargetManagerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IVariableValueEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapter2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IWatchExpressionFactoryAdapterExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImportBreakpointsOperation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchAsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "LaunchShortcutsAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenLaunchDialogAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RelaunchLastAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerBreakpointTypesActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerEnableDisableBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerRunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RulerToggleBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "RunToLineHandler.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleBreakpointAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleMethodBreakpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ToggleWatchpointActionDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FileLink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleColorProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTracker.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleLineTrackerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "contexts" + }, + "children": [ + { + "element": { + "name": "AbstractDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "DebugContextEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextProvider2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IDebugContextService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTrigger.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISuspendTriggerListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "memory" + }, + "children": [ + { + "element": { + "name": "AbstractMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTableRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "AbstractTextRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryBlockTablePresentation.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingBindingsProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSite2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingSynchronizationService.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingType.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IMemoryRenderingTypeDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IRepositionableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IResettableMemoryRendering.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MemoryRenderingElement.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + }, + { + "element": { + "name": "sourcelookup" + }, + "children": [ + { + "element": { + "name": "AbstractSourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditor.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CommonSourceNotFoundEditorInput.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceContainerBrowser.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceDisplay.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ISourceLookupResult.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SourceLookupTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetSourceContainer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "stringsubstitution" + }, + "children": [ + { + "element": { + "name": "IArgumentSelector.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.console" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "clcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "cview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dlcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "dview16" + }, + "children": [ + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "elcl16" + }, + "children": [ + { + "element": { + "name": "clear_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "clear_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "lock_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con.png" + }, + "incompressible": true + }, + { + "element": { + "name": "new_con@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin.png" + }, + "incompressible": true + }, + { + "element": { + "name": "pin@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co.png" + }, + "incompressible": true + }, + { + "element": { + "name": "rem_co@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap.png" + }, + "incompressible": true + }, + { + "element": { + "name": "wordwrap@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "eview16" + }, + "children": [ + { + "element": { + "name": "console_view.gif" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view.png" + }, + "incompressible": true + }, + { + "element": { + "name": "console_view@2x.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "consoleFactories.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePageParticipants.exsd" + }, + "incompressible": true + }, + { + "element": { + "name": "consolePatternMatchListeners.exsd" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "scripts" + }, + "children": [ + { + "element": { + "name": "exportplugin.xml" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "src" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "AbstractConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleDocumentPartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsolePageParticipant.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IHyperlink2.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleInputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleOutputStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPatternMatchListenerDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IScrollLockStateProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "MessageConsoleStream.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchEvent.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsole.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "actions" + }, + "children": [ + { + "element": { + "name": "ClearOutputAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "CloseConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TextViewerGotoLineAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "package.html" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "console" + }, + "children": [ + { + "element": { + "name": "ConsoleDocument.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDocumentAdapter.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleDropDownAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleFactoryExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleHyperlinkPosition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleManager.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePageParticipantExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePatternMatcher.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsolePluginImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleResourceBundleMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleTypePropertyTester.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleUIPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleView.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleViewConsoleFactory.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ConsoleWorkbenchPart.java" + }, + "incompressible": true + }, + { + "element": { + "name": "FollowHyperlinkAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "HyperlinkUpdater.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IConsoleHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IInternalConsoleConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartition.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsolePartitioner.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IOConsoleViewer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListener.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PatternMatchListenerExtension.java" + }, + "incompressible": true + }, + { + "element": { + "name": "PinConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ScrollLockAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ShowConsoleAction.java" + }, + "incompressible": true + }, + { + "element": { + "name": "StreamDecoder.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WordWrapAction.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "org.eclipse.ui.externaltools" + }, + "children": [ + { + "element": { + "name": ".classpath" + }, + "incompressible": true + }, + { + "element": { + "name": ".gitignore" + }, + "incompressible": true + }, + { + "element": { + "name": ".project" + }, + "incompressible": true + }, + { + "element": { + "name": ".settings" + }, + "children": [ + { + "element": { + "name": ".api_filters" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.resources.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.core.runtime.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.core.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.jdt.ui.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.api.tools.prefs" + }, + "incompressible": true + }, + { + "element": { + "name": "org.eclipse.pde.prefs" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "External Tools Base" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsBuildTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsBuilderTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsLaunchConfigurationMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUtil.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IgnoreWhiteSpaceComparator.java" + }, + "incompressible": true + }, + { + "element": { + "name": "WorkingSetComparator.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "menu" + }, + "children": [ + { + "element": { + "name": "ExternalToolMenuDelegate.java" + }, + "incompressible": true + }, + { + "element": { + "name": "OpenExternalToolsConfigurations.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "model" + }, + "children": [ + { + "element": { + "name": "BuilderUtils.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsImages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsModelMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPlugin.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferenceInitializer.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IExternalToolsHelpContextIds.java" + }, + "incompressible": true + }, + { + "element": { + "name": "IPreferenceConstants.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ImageDescriptorRegistry.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "BuilderLabelProvider.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuilderPropertyPage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "EditCommandDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsPreferencePage.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsUIMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "FileSelectionDialog.java" + }, + "incompressible": true + }, + { + "element": { + "name": "TreeAndListGroup.java" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "variables" + }, + "children": [ + { + "element": { + "name": "BuildFilesResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildProjectResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "BuildTypeResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "SystemPathResolver.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "VariableMessages.properties" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "META-INF" + }, + "children": [ + { + "element": { + "name": "MANIFEST.MF" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "Program Tools Support" + }, + "children": [ + { + "element": { + "name": "org" + }, + "children": [ + { + "element": { + "name": "eclipse" + }, + "children": [ + { + "element": { + "name": "ui" + }, + "children": [ + { + "element": { + "name": "externaltools" + }, + "children": [ + { + "element": { + "name": "internal" + }, + "children": [ + { + "element": { + "name": "program" + }, + "children": [ + { + "element": { + "name": "launchConfigurations" + }, + "children": [ + { + "element": { + "name": "ExternalToolsProgramMessages.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ExternalToolsProgramMessages.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramBuilderTabGroup.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramMainTab.java" + }, + "incompressible": true + }, + { + "element": { + "name": "ProgramTabGroup.java" + }, + "incompressible": true + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "about.html" + }, + "incompressible": true + }, + { + "element": { + "name": "build.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "icons" + }, + "children": [ + { + "element": { + "name": "full" + }, + "children": [ + { + "element": { + "name": "dtool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "etool16" + }, + "children": [ + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "obj16" + }, + "children": [ + { + "element": { + "name": "build_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "build_tab@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder.png" + }, + "incompressible": true + }, + { + "element": { + "name": "builder@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath.png" + }, + "incompressible": true + }, + { + "element": { + "name": "classpath@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools.png" + }, + "incompressible": true + }, + { + "element": { + "name": "external_tools@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool.png" + }, + "incompressible": true + }, + { + "element": { + "name": "invalid_build_tool@2x.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab.png" + }, + "incompressible": true + }, + { + "element": { + "name": "main_tab@2x.png" + }, + "incompressible": true + } + ] + }, + { + "element": { + "name": "wizban" + }, + "children": [ + { + "element": { + "name": "ext_tools_wiz.png" + }, + "incompressible": true + } + ] + } + ] + } + ] + }, + { + "element": { + "name": "plugin.properties" + }, + "incompressible": true + }, + { + "element": { + "name": "plugin.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + }, + { + "element": { + "name": "schema" + }, + "children": [ + { + "element": { + "name": "configurationDuplicationMaps.exsd" + }, + "incompressible": true + } + ] + } + ] + }, + { + "element": { + "name": "pom.xml" + }, + "incompressible": true + } + ] + } +] \ No newline at end of file diff --git a/test/tree/public/index.html b/test/tree/public/index.html index 7c83e9b045..17c88461c4 100644 --- a/test/tree/public/index.html +++ b/test/tree/public/index.html @@ -44,7 +44,7 @@ require.config({ baseUrl: '/static' }); - require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { + require(['vs/base/browser/ui/tree/indexTree', 'vs/base/browser/ui/tree/compressedObjectTree', 'vs/base/browser/ui/tree/asyncDataTree', 'vs/base/browser/ui/tree/dataTree', 'vs/base/browser/ui/tree/tree', 'vs/base/common/iterator'], ({ IndexTree }, { CompressedObjectTree }, { AsyncDataTree }, { DataTree }, { TreeVisibility }, { iter }) => { function createIndexTree(opts) { opts = opts || {}; @@ -100,6 +100,57 @@ return { tree, treeFilter }; } + function createCompressedObjectTree(opts) { + opts = opts || {}; + + const delegate = { + getHeight() { return 22; }, + getTemplateId() { return 'template'; }, + hasDynamicHeight() { return true; } + }; + + const renderer = { + templateId: 'template', + renderTemplate(container) { return container; }, + renderElement(element, index, container) { + if (element.element.elements.length > 1) { + container.innerHTML = `🙈 ${element.element.elements.map(el => el.name).join('/')}`; + } else { + container.innerHTML = element.element.elements[0].name; + } + }, + disposeElement() { }, + disposeTemplate() { } + }; + + const treeFilter = new class { + constructor() { + this.pattern = null; + let timeout; + filter.oninput = () => { + clearTimeout(timeout); + timeout = setTimeout(() => this.updatePattern(), 300); + }; + } + updatePattern() { + if (!filter.value) { + this.pattern = null; + } else { + this.pattern = new RegExp(filter.value, 'i'); + } + + perf('refilter', () => tree.refilter()); + } + filter(el) { + return (this.pattern ? this.pattern.test(el) : true) ? TreeVisibility.Visible : TreeVisibility.Recurse; + } + }; + + const tree = new CompressedObjectTree(container, delegate, [renderer], { ...opts, filter: treeFilter, setRowLineHeight: false, collapseByDefault: true, setRowLineHeight: true }); + + return { tree, treeFilter }; + } + function createAsyncDataTree() { const delegate = { getHeight() { return 22; }, @@ -155,7 +206,7 @@ getChildren(element) { return new Promise((c, e) => { const xhr = new XMLHttpRequest(); - xhr.open('GET', element ? `/api/readdir?path=${element.element.path}` : '/api/readdir'); + xhr.open('GET', element ? `/ api / readdir ? path = ${element.element.path} ` : '/api/readdir'); xhr.send(); xhr.onreadystatechange = function () { if (this.readyState == 4 && this.status == 200) { @@ -258,7 +309,7 @@ const errors = []; for (let j = 1; j <= 3; j++) { - errors.push({ element: `error #${j}` }); + errors.push({ element: `error #${j} ` }); } files.push({ element: `file #${i}`, children: errors }); @@ -289,6 +340,23 @@ break; } + case '?compressed': { + const { tree, treeFilter } = createCompressedObjectTree(); + + expandall.onclick = () => perf('expand all', () => tree.expandAll()); + collapseall.onclick = () => perf('collapse all', () => tree.collapseAll()); + + const xhr = new XMLHttpRequest(); + xhr.open('GET', '/compressed.json'); + xhr.send(); + xhr.onreadystatechange = function () { + if (this.readyState == 4 && this.status == 200) { + tree.setChildren(null, JSON.parse(this.responseText)); + } + }; + + break; + } case '?height': { const { tree, treeFilter } = createIndexTree({ supportDynamicHeights: true }); diff --git a/test/tree/tree.js b/test/tree/tree.js new file mode 100644 index 0000000000..7f27ffaa3e --- /dev/null +++ b/test/tree/tree.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 path = require('path'); +const fs = require('fs'); + +function collect(location) { + const element = { name: path.basename(location) }; + const stat = fs.statSync(location); + + if (!stat.isDirectory()) { + return { element, incompressible: true }; + } + + const children = fs.readdirSync(location) + .map(child => path.join(location, child)) + .map(collect); + + return { element, children }; +} + +console.log(JSON.stringify(collect(process.cwd()))); diff --git a/yarn.lock b/yarn.lock index 3a233d3649..2a952624fb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4014,14 +4014,15 @@ gulp-plumber@^1.2.0: plugin-error "^0.1.2" through2 "^2.0.3" -gulp-remote-src@^0.4.4: - version "0.4.4" - resolved "https://registry.yarnpkg.com/gulp-remote-src/-/gulp-remote-src-0.4.4.tgz#4a4d18fac0ffedde94a7855953de90db00a1d1b1" - integrity sha512-mo7lGgZmNXyTbcUzfjSnUVkx1pnqqiwv/pPaIrYdTO77hq0WNTxXLAzQdoYOnyJ0mfVLNmNl9AGqWLiAzTPMMA== +gulp-remote-retry-src@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/gulp-remote-retry-src/-/gulp-remote-retry-src-0.6.0.tgz#fdcb5d5c9e67c31ae378a2a886ddad3d47913bb1" + integrity sha512-lFxpwwbM/GEIdYiNumxiUcPHZUROFJaF1zTBne1H8b3Pwx6Te6O9uEYp++JZPP62jdheOWcHUTBREiMkpdbm4Q== dependencies: event-stream "3.3.4" node.extend "~1.1.2" request "^2.88.0" + requestretry "^4.0.0" through2 "~2.0.3" vinyl "~2.0.1" @@ -4268,6 +4269,13 @@ has@^1.0.1: dependencies: function-bind "^1.0.2" +has@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" + integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== + dependencies: + function-bind "^1.1.1" + hash-base@^3.0.0: version "3.0.4" resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" @@ -6279,11 +6287,12 @@ node-pty@0.9.0-beta19: nan "^2.13.2" node.extend@~1.1.2: - version "1.1.6" - resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.6.tgz#a7b882c82d6c93a4863a5504bd5de8ec86258b96" - integrity sha1-p7iCyC1sk6SGOlUEvV3o7IYli5Y= + version "1.1.8" + resolved "https://registry.yarnpkg.com/node.extend/-/node.extend-1.1.8.tgz#0aab3e63789f4e6d68b42bc00073ad1881243cf0" + integrity sha512-L/dvEBwyg3UowwqOUTyDsGBU6kjBQOpOhshio9V3i3BMPv5YUb9+mWNN8MK0IbWqT0AqaTSONZf0aTuMMahWgA== dependencies: - is "^3.1.0" + has "^1.0.3" + is "^3.2.1" noop-logger@^0.1.1: version "0.1.1" @@ -7956,6 +7965,15 @@ request@^2.86.0, request@^2.88.0: tunnel-agent "^0.6.0" uuid "^3.3.2" +requestretry@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/requestretry/-/requestretry-4.0.0.tgz#4e9e7280a7d8561bf33e9925264cf026e2be3e89" + integrity sha512-ST8m0+5FQH2FA+gbzUQyOQjUwHf22kbPQnd6TexveR0p+2UV1YYBg+Roe7BnKQ1Bb/+LtJwwm0QzxK2NA20Cug== + dependencies: + extend "^3.0.2" + lodash "^4.17.10" + when "^3.7.7" + require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -10025,6 +10043,11 @@ webpack@^4.16.5, webpack@^4.7.0: watchpack "^1.5.0" webpack-sources "^1.0.1" +when@^3.7.7: + version "3.7.8" + resolved "https://registry.yarnpkg.com/when/-/when-3.7.8.tgz#c7130b6a7ea04693e842cdc9e7a1f2aa39a39f82" + integrity sha1-xxMLan6gRpPoQs3J56Hyqjmjn4I= + whet.extend@~0.9.9: version "0.9.9" resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" @@ -10203,20 +10226,20 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" -xterm-addon-search@0.2.0-beta2: - version "0.2.0-beta2" - resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta2.tgz#c3173f0a6f207ee9f1848849174ee5d6b6ce8262" - integrity sha512-XEcwi2TeFGk2MuIFjiI/OpVXSNO5dGQBvHH3o+9KzqG3ooVqhhDqzwxs092QGNcNCGh8hGn/PWZiczaBBnKm/g== +xterm-addon-search@0.2.0-beta3: + version "0.2.0-beta3" + resolved "https://registry.yarnpkg.com/xterm-addon-search/-/xterm-addon-search-0.2.0-beta3.tgz#710ce14658e269c5a4791f5a9e2f520883a2e62b" + integrity sha512-KzVdkEtGbKJe9ER2TmrI7XjF/wUq1lir9U63vPJi0t2ymQvIECl1V63f9QtOp1vvpdhbZiXBxO+vGTj+y0tRow== xterm-addon-web-links@0.1.0-beta10: version "0.1.0-beta10" resolved "https://registry.yarnpkg.com/xterm-addon-web-links/-/xterm-addon-web-links-0.1.0-beta10.tgz#610fa9773a2a5ccd41c1c83ba0e2dd2c9eb66a23" integrity sha512-xfpjy0V6bB4BR44qIgZQPoCMVakxb65gMscPkHpO//QxvUxKzabV3dxOsIbeZRFkUGsWTFlvz2OoaBLoNtv5gg== -xterm@3.15.0-beta71: - version "3.15.0-beta71" - resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta71.tgz#2728c9800ca3b08423e835e9504bd1f4b5de6253" - integrity sha512-8M/cLaxZ+iDopRxLPdPfKuDGaNNyYTdCeytdxjMSH0N7dZzbx6fbaEygQdCrV5pO9cGnT92MefSjVPGRXRiBLA== +xterm@3.15.0-beta89: + version "3.15.0-beta89" + resolved "https://registry.yarnpkg.com/xterm/-/xterm-3.15.0-beta89.tgz#255962e2595deefb42b8c0043001256526163a3f" + integrity sha512-rNaoUamacPRg+ejbKDGRDNqR3SZ3Uf/pUW0mO+FF25/lIgdLq8x7RgZVBgFweCZ/dijPjxoyMcgfNDTH9h8LOg== y18n@^3.2.1: version "3.2.1"